3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
21 #include "BufferList.h"
24 #include "ConverterCache.h"
25 #include "Converter.h"
26 #include "CutAndPaste.h"
28 #include "ErrorList.h"
33 #include "LyXAction.h"
36 #include "MenuBackend.h"
37 #include "ModuleList.h"
40 #include "ServerSocket.h"
42 #include "TextClassList.h"
43 #include "ToolbarBackend.h"
45 #include "frontends/alert.h"
46 #include "frontends/Application.h"
48 #include "support/debug.h"
49 #include "support/environment.h"
50 #include "support/ExceptionMessage.h"
51 #include "support/filetools.h"
52 #include "support/gettext.h"
53 #include "support/lstrings.h"
54 #include "support/Messages.h"
55 #include "support/os.h"
56 #include "support/Package.h"
57 #include "support/Path.h"
58 #include "support/Systemcall.h"
60 #include <boost/bind.hpp>
61 #include <boost/scoped_ptr.hpp>
72 using namespace lyx::support;
76 namespace Alert = frontend::Alert;
77 namespace os = support::os;
81 // Are we using the GUI at all? We default to true and this is changed
82 // to false when the export feature is used.
86 bool quitting; // flag, that we are quitting the program
90 // Filled with the command line arguments "foo" of "-sysdir foo" or
92 string cl_system_support;
93 string cl_user_support;
99 void showFileError(string const & error)
101 Alert::warning(_("Could not read configuration file"),
102 bformat(_("Error while reading the configuration file\n%1$s.\n"
103 "Please check your installation."), from_utf8(error)));
107 void reconfigureUserLyXDir()
109 string const configure_command = package().configure_command();
111 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
112 PathChanger p(package().user_support());
114 one.startscript(Systemcall::Wait, configure_command);
115 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
121 /// The main application class private implementation.
126 // Set the default User Interface language as soon as possible.
127 // The language used will be derived from the environment
129 messages_["GUI"] = Messages();
131 /// our function handler
134 BufferList buffer_list_;
136 KeyMap toplevel_keymap_;
138 CmdDef toplevel_cmddef_;
140 boost::scoped_ptr<Server> lyx_server_;
142 boost::scoped_ptr<ServerSocket> lyx_socket_;
144 boost::scoped_ptr<frontend::Application> application_;
145 /// lyx session, containing lastfiles, lastfilepos, and lastopened
146 boost::scoped_ptr<Session> session_;
148 /// Files to load at start.
149 vector<string> files_to_load_;
151 /// The messages translators.
152 map<string, Messages> messages_;
154 /// The file converters.
155 Converters converters_;
157 // The system converters copy after reading lyxrc.defaults.
158 Converters system_converters_;
163 Movers system_movers_;
165 /// has this user started lyx for the first time?
167 /// the parsed command line batch command if any
168 string batch_command;
172 frontend::Application * theApp()
175 return singleton_->pimpl_->application_.get();
187 void LyX::exit(int exit_code) const
190 // Something wrong happened so better save everything, just in
195 // Properly crash in debug mode in order to get a useful backtrace.
199 // In release mode, try to exit gracefully.
201 theApp()->exit(exit_code);
209 BOOST_ASSERT(singleton_);
214 LyX const & LyX::cref()
216 BOOST_ASSERT(singleton_);
229 BufferList & LyX::bufferList()
231 return pimpl_->buffer_list_;
235 BufferList const & LyX::bufferList() const
237 return pimpl_->buffer_list_;
241 Session & LyX::session()
243 BOOST_ASSERT(pimpl_->session_.get());
244 return *pimpl_->session_.get();
248 Session const & LyX::session() const
250 BOOST_ASSERT(pimpl_->session_.get());
251 return *pimpl_->session_.get();
255 LyXFunc & LyX::lyxFunc()
257 return pimpl_->lyxfunc_;
261 LyXFunc const & LyX::lyxFunc() const
263 return pimpl_->lyxfunc_;
267 Server & LyX::server()
269 BOOST_ASSERT(pimpl_->lyx_server_.get());
270 return *pimpl_->lyx_server_.get();
274 Server const & LyX::server() const
276 BOOST_ASSERT(pimpl_->lyx_server_.get());
277 return *pimpl_->lyx_server_.get();
281 ServerSocket & LyX::socket()
283 BOOST_ASSERT(pimpl_->lyx_socket_.get());
284 return *pimpl_->lyx_socket_.get();
288 ServerSocket const & LyX::socket() const
290 BOOST_ASSERT(pimpl_->lyx_socket_.get());
291 return *pimpl_->lyx_socket_.get();
295 frontend::Application & LyX::application()
297 BOOST_ASSERT(pimpl_->application_.get());
298 return *pimpl_->application_.get();
302 frontend::Application const & LyX::application() const
304 BOOST_ASSERT(pimpl_->application_.get());
305 return *pimpl_->application_.get();
309 KeyMap & LyX::topLevelKeymap()
311 return pimpl_->toplevel_keymap_;
315 CmdDef & LyX::topLevelCmdDef()
317 return pimpl_->toplevel_cmddef_;
321 Converters & LyX::converters()
323 return pimpl_->converters_;
327 Converters & LyX::systemConverters()
329 return pimpl_->system_converters_;
333 KeyMap const & LyX::topLevelKeymap() const
335 return pimpl_->toplevel_keymap_;
339 Messages & LyX::getMessages(string const & language)
341 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
343 if (it != pimpl_->messages_.end())
346 pair<map<string, Messages>::iterator, bool> result =
347 pimpl_->messages_.insert(make_pair(language, Messages(language)));
349 BOOST_ASSERT(result.second);
350 return result.first->second;
354 Messages & LyX::getGuiMessages()
356 return pimpl_->messages_["GUI"];
360 void LyX::setGuiLanguage(string const & language)
362 pimpl_->messages_["GUI"] = Messages(language);
366 int LyX::exec(int & argc, char * argv[])
368 // Here we need to parse the command line. At least
369 // we need to parse for "-dbg" and "-help"
370 easyParse(argc, argv);
373 init_package(to_utf8(from_local8bit(argv[0])),
374 cl_system_support, cl_user_support,
375 top_build_dir_is_one_level_up);
376 } catch (ExceptionMessage const & message) {
377 if (message.type_ == ErrorException) {
378 Alert::error(message.title_, message.details_);
380 } else if (message.type_ == WarningException) {
381 Alert::warning(message.title_, message.details_);
385 // Reinit the messages machinery in case package() knows
386 // something interesting about the locale directory.
390 // FIXME: create a ConsoleApplication
391 int exit_status = init(argc, argv);
399 if (pimpl_->batch_command.empty() || pimpl_->buffer_list_.empty()) {
404 BufferList::iterator begin = pimpl_->buffer_list_.begin();
406 bool final_success = false;
407 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
409 if (buf != buf->masterBuffer())
411 bool success = false;
412 buf->dispatch(pimpl_->batch_command, &success);
413 final_success |= success;
416 return !final_success;
419 // Let the frontend parse and remove all arguments that it knows
420 pimpl_->application_.reset(createApplication(argc, argv));
422 // Parse and remove all known arguments in the LyX singleton
423 // Give an error for all remaining ones.
424 int exit_status = init(argc, argv);
426 // Kill the application object before exiting.
427 pimpl_->application_.reset();
434 /* Create a CoreApplication class that will provide the main event loop
435 * and the socket callback registering. With Qt4, only QtCore
436 * library would be needed.
437 * When this is done, a server_mode could be created and the following two
438 * line would be moved out from here.
440 // Note: socket callback must be registered after init(argc, argv)
441 // such that package().temp_dir() is properly initialized.
442 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
443 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
444 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
446 // Start the real execution loop.
447 exit_status = pimpl_->application_->exec();
455 void LyX::prepareExit()
457 // Clear the clipboard and selection stack:
458 cap::clearCutStack();
459 cap::clearSelection();
461 // Set a flag that we do quitting from the program,
462 // so no refreshes are necessary.
465 // close buffers first
466 pimpl_->buffer_list_.closeAll();
468 // register session changes and shutdown server and socket
470 if (pimpl_->session_)
471 pimpl_->session_->writeFile();
472 pimpl_->session_.reset();
473 pimpl_->lyx_server_.reset();
474 pimpl_->lyx_socket_.reset();
477 // do any other cleanup procedures now
478 if (package().temp_dir() != package().system_temp_dir()) {
479 LYXERR(Debug::INFO, "Deleting tmp dir "
480 << package().temp_dir().absFilename());
482 if (!package().temp_dir().destroyDirectory()) {
483 docstring const msg =
484 bformat(_("Unable to remove the temporary directory %1$s"),
485 from_utf8(package().temp_dir().absFilename()));
486 Alert::warning(_("Unable to remove temporary directory"), msg);
490 // Kill the application object before exiting. This avoids crashes
491 // when exiting on Linux.
492 if (pimpl_->application_)
493 pimpl_->application_.reset();
497 void LyX::earlyExit(int status)
499 BOOST_ASSERT(pimpl_->application_.get());
500 // LyX::pimpl_::application_ is not initialised at this
501 // point so it's safe to just exit after some cleanup.
507 int LyX::init(int & argc, char * argv[])
509 // check for any spurious extra arguments
510 // other than documents
511 for (int argi = 1; argi < argc ; ++argi) {
512 if (argv[argi][0] == '-') {
514 bformat(_("Wrong command line option `%1$s'. Exiting."),
515 from_utf8(argv[argi]))) << endl;
520 // Initialization of LyX (reads lyxrc and more)
521 LYXERR(Debug::INIT, "Initializing LyX::init...");
522 bool success = init();
523 LYXERR(Debug::INIT, "Initializing LyX::init...done");
527 // Remaining arguments are assumed to be files to load.
528 for (int argi = argc - 1; argi >= 1; --argi)
529 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
532 pimpl_->files_to_load_.push_back(
533 i18nLibFileSearch("examples", "splash.lyx").absFilename());
540 void LyX::addFileToLoad(string const & fname)
542 vector<string>::const_iterator cit = find(
543 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
546 if (cit == pimpl_->files_to_load_.end())
547 pimpl_->files_to_load_.push_back(fname);
551 void LyX::loadFiles()
553 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
554 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
556 for (; it != end; ++it) {
557 // get absolute path of file and add ".lyx" to
558 // the filename if necessary
559 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
565 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
566 if (buf->loadLyXFile(fname)) {
567 ErrorList const & el = buf->errorList("Parse");
569 for_each(el.begin(), el.end(),
570 boost::bind(&LyX::printError, this, _1));
573 pimpl_->buffer_list_.release(buf);
578 void LyX::execBatchCommands()
580 // The advantage of doing this here is that the event loop
581 // is already started. So any need for interaction will be
584 // if reconfiguration is needed.
585 while (textclasslist.empty()) {
586 switch (Alert::prompt(
587 _("No textclass is found"),
588 _("LyX cannot continue because no textclass is found. "
589 "You can either reconfigure normally, or reconfigure using "
590 "default textclasses, or quit LyX."),
597 // regular reconfigure
598 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
601 // reconfigure --without-latex-config
602 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
603 " --without-latex-config"));
606 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
611 // create the first main window
612 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
614 if (!pimpl_->files_to_load_.empty()) {
615 // if some files were specified at command-line we assume that the
616 // user wants to edit *these* files and not to restore the session.
617 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
618 pimpl_->lyxfunc_.dispatch(
619 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
621 // clear this list to save a few bytes of RAM
622 pimpl_->files_to_load_.clear();
625 pimpl_->application_->restoreGuiSession();
627 // Execute batch commands if available
628 if (pimpl_->batch_command.empty())
631 LYXERR(Debug::INIT, "About to handle -x '" << pimpl_->batch_command << '\'');
633 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
640 The SIGHUP signal does not exist on Windows and does not need to be handled.
642 Windows handles SIGFPE and SIGSEGV signals as expected.
644 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
645 cause a new thread to be spawned. This may well result in unexpected
646 behaviour by the single-threaded LyX.
648 SIGTERM signals will come only from another process actually sending
649 that signal using 'raise' in Windows' POSIX compatability layer. It will
650 not come from the general "terminate process" methods that everyone
651 actually uses (and which can't be trapped). Killing an app 'politely' on
652 Windows involves first sending a WM_CLOSE message, something that is
653 caught already by the Qt frontend.
655 For more information see:
657 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
658 ...signals are mostly useless on Windows for a variety of reasons that are
661 'UNIX Application Migration Guide, Chapter 9'
662 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
664 'How To Terminate an Application "Cleanly" in Win32'
665 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
669 static void error_handler(int err_sig)
671 // Throw away any signals other than the first one received.
672 static sig_atomic_t handling_error = false;
675 handling_error = true;
677 // We have received a signal indicating a fatal error, so
678 // try and save the data ASAP.
679 LyX::cref().emergencyCleanup();
681 // These lyxerr calls may or may not work:
683 // Signals are asynchronous, so the main program may be in a very
684 // fragile state when a signal is processed and thus while a signal
685 // handler function executes.
686 // In general, therefore, we should avoid performing any
687 // I/O operations or calling most library and system functions from
690 // This shouldn't matter here, however, as we've already invoked
695 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
699 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
702 lyxerr << "\nlyx: SIGSEGV signal caught\n"
703 "Sorry, you have found a bug in LyX. "
704 "Please read the bug-reporting instructions "
705 "in Help->Introduction and send us a bug report, "
706 "if necessary. Thanks !\nBye." << endl;
714 // Deinstall the signal handlers
716 signal(SIGHUP, SIG_DFL);
718 signal(SIGINT, SIG_DFL);
719 signal(SIGFPE, SIG_DFL);
720 signal(SIGSEGV, SIG_DFL);
721 signal(SIGTERM, SIG_DFL);
724 if (err_sig == SIGSEGV ||
725 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
727 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
736 void LyX::printError(ErrorItem const & ei)
738 docstring tmp = _("LyX: ") + ei.error + char_type(':')
740 cerr << to_utf8(tmp) << endl;
747 signal(SIGHUP, error_handler);
749 signal(SIGFPE, error_handler);
750 signal(SIGSEGV, error_handler);
751 signal(SIGINT, error_handler);
752 signal(SIGTERM, error_handler);
753 // SIGPIPE can be safely ignored.
755 lyxrc.tempdir_path = package().temp_dir().absFilename();
756 lyxrc.document_path = package().document_dir().absFilename();
758 if (lyxrc.example_path.empty()) {
759 lyxrc.example_path = addPath(package().system_support().absFilename(),
762 if (lyxrc.template_path.empty()) {
763 lyxrc.template_path = addPath(package().system_support().absFilename(),
768 // Read configuration files
771 // This one may have been distributed along with LyX.
772 if (!readRcFile("lyxrc.dist"))
775 // Set the language defined by the distributor.
776 //setGuiLanguage(lyxrc.gui_language);
778 // Set the PATH correctly.
779 #if !defined (USE_POSIX_PACKAGING)
780 // Add the directory containing the LyX executable to the path
781 // so that LyX can find things like tex2lyx.
782 if (package().build_support().empty())
783 prependEnvPath("PATH", package().binary_dir().absFilename());
785 if (!lyxrc.path_prefix.empty())
786 prependEnvPath("PATH", lyxrc.path_prefix);
788 // Check that user LyX directory is ok.
789 if (queryUserLyXDir(package().explicit_user_support()))
790 reconfigureUserLyXDir();
792 // no need for a splash when there is no GUI
797 // This one is generated in user_support directory by lib/configure.py.
798 if (!readRcFile("lyxrc.defaults"))
801 // Query the OS to know what formats are viewed natively
802 formats.setAutoOpen();
804 // Read lyxrc.dist again to be able to override viewer auto-detection.
805 readRcFile("lyxrc.dist");
807 system_lyxrc = lyxrc;
808 system_formats = formats;
809 pimpl_->system_converters_ = pimpl_->converters_;
810 pimpl_->system_movers_ = pimpl_->movers_;
811 system_lcolor = lcolor;
813 // This one is edited through the preferences dialog.
814 if (!readRcFile("preferences"))
817 if (!readEncodingsFile("encodings", "unicodesymbols"))
819 if (!readLanguagesFile("languages"))
823 LYXERR(Debug::INIT, "Reading layouts...");
829 // read keymap and ui files in batch mode as well
830 // because InsetInfo needs to know these to produce
831 // the correct output
833 // Set the language defined by the user.
834 //setGuiLanguage(lyxrc.gui_language);
836 // Set up command definitions
837 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
840 pimpl_->toplevel_keymap_.read("site");
841 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
842 // load user bind file user.bind
843 pimpl_->toplevel_keymap_.read("user");
845 pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
848 if (use_gui && !readUIFile(lyxrc.ui_file))
851 if (lyxerr.debugging(Debug::LYXRC))
854 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
855 if (!lyxrc.path_prefix.empty())
856 prependEnvPath("PATH", lyxrc.path_prefix);
858 FileName const document_path(lyxrc.document_path);
859 if (document_path.exists() && document_path.isDirectory())
860 package().document_dir() = document_path;
862 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
863 if (package().temp_dir().empty()) {
864 Alert::error(_("Could not create temporary directory"),
865 bformat(_("Could not create a temporary directory in\n"
866 "%1$s. Make sure that this\n"
867 "path exists and is writable and try again."),
868 from_utf8(lyxrc.tempdir_path)));
869 // createLyXTmpDir() tries sufficiently hard to create a
870 // usable temp dir, so the probability to come here is
871 // close to zero. We therefore don't try to overcome this
872 // problem with e.g. asking the user for a new path and
873 // trying again but simply exit.
877 LYXERR(Debug::INIT, "LyX tmp dir: `"
878 << package().temp_dir().absFilename() << '\'');
880 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
881 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
883 // This must happen after package initialization and after lyxrc is
884 // read, therefore it can't be done by a static object.
885 ConverterCache::init();
891 void LyX::emergencyCleanup() const
893 // what to do about tmpfiles is non-obvious. we would
894 // like to delete any we find, but our lyxdir might
895 // contain documents etc. which might be helpful on
898 pimpl_->buffer_list_.emergencyWriteAll();
900 if (pimpl_->lyx_server_)
901 pimpl_->lyx_server_->emergencyCleanup();
902 pimpl_->lyx_server_.reset();
903 pimpl_->lyx_socket_.reset();
908 void LyX::deadKeyBindings(KeyMap * kbmap)
910 // bindKeyings for transparent handling of deadkeys
911 // The keysyms are gotten from XFree86 X11R6
912 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
913 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
914 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
915 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
916 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
917 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
918 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
919 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
920 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
921 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
922 // nothing with this name
923 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
924 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
925 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
926 // nothing with this name either...
927 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
928 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
929 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
930 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
934 // return true if file does not exist or is older than configure.py.
935 static bool needsUpdate(string const & file)
937 // We cannot initialize configure_script directly because the package
938 // is not initialized yet when static objects are constructed.
939 static FileName configure_script;
940 static bool firstrun = true;
943 FileName(addName(package().system_support().absFilename(),
949 FileName(addName(package().user_support().absFilename(), file));
950 return !absfile.exists()
951 || configure_script.lastModified() > absfile.lastModified();
955 bool LyX::queryUserLyXDir(bool explicit_userdir)
957 // Does user directory exist?
958 FileName const sup = package().user_support();
959 if (sup.exists() && sup.isDirectory()) {
962 return needsUpdate("lyxrc.defaults")
963 || needsUpdate("lyxmodules.lst")
964 || needsUpdate("textclass.lst")
965 || needsUpdate("packages.lst");
968 first_start = !explicit_userdir;
970 // If the user specified explicitly a directory, ask whether
971 // to create it. If the user says "no", then exit.
972 if (explicit_userdir &&
974 _("Missing user LyX directory"),
975 bformat(_("You have specified a non-existent user "
976 "LyX directory, %1$s.\n"
977 "It is needed to keep your own configuration."),
978 from_utf8(package().user_support().absFilename())),
980 _("&Create directory"),
982 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
983 earlyExit(EXIT_FAILURE);
986 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
987 from_utf8(sup.absFilename()))) << endl;
989 if (!sup.createDirectory(0755)) {
990 // Failed, so let's exit.
991 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
993 earlyExit(EXIT_FAILURE);
1000 bool LyX::readRcFile(string const & name)
1002 LYXERR(Debug::INIT, "About to read " << name << "... ");
1004 FileName const lyxrc_path = libFileSearch(string(), name);
1005 if (!lyxrc_path.empty()) {
1006 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
1007 if (lyxrc.read(lyxrc_path) < 0) {
1008 showFileError(name);
1012 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
1018 // Read the ui file `name'
1019 bool LyX::readUIFile(string const & name, bool include)
1029 struct keyword_item uitags[ui_last - 1] = {
1030 { "include", ui_include },
1031 { "menuset", ui_menuset },
1032 { "toolbars", ui_toolbars },
1033 { "toolbarset", ui_toolbarset }
1036 // Ensure that a file is read only once (prevents include loops)
1037 static list<string> uifiles;
1038 list<string>::const_iterator it = uifiles.begin();
1039 list<string>::const_iterator end = uifiles.end();
1040 it = find(it, end, name);
1042 LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1043 << "Is this an include loop?");
1047 LYXERR(Debug::INIT, "About to read " << name << "...");
1052 ui_path = libFileSearch("ui", name, "inc");
1053 if (ui_path.empty())
1054 ui_path = libFileSearch("ui",
1055 changeExtension(name, "inc"));
1058 ui_path = libFileSearch("ui", name, "ui");
1060 if (ui_path.empty()) {
1061 LYXERR(Debug::INIT, "Could not find " << name);
1062 showFileError(name);
1066 uifiles.push_back(name);
1068 LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1069 Lexer lex(uitags, ui_last - 1);
1070 lex.setFile(ui_path);
1072 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1076 if (lyxerr.debugging(Debug::PARSER))
1077 lex.printTable(lyxerr);
1079 while (lex.isOK()) {
1080 switch (lex.lex()) {
1083 string const file = lex.getString();
1084 if (!readUIFile(file, true))
1089 theApp()->menuBackend().read(lex);
1093 toolbarbackend.readToolbars(lex);
1097 toolbarbackend.readToolbarSettings(lex);
1101 if (!rtrim(lex.getString()).empty())
1102 lex.printError("LyX::ReadUIFile: "
1103 "Unknown menu tag: `$$Token'");
1111 // Read the languages file `name'
1112 bool LyX::readLanguagesFile(string const & name)
1114 LYXERR(Debug::INIT, "About to read " << name << "...");
1116 FileName const lang_path = libFileSearch(string(), name);
1117 if (lang_path.empty()) {
1118 showFileError(name);
1121 languages.read(lang_path);
1126 // Read the encodings file `name'
1127 bool LyX::readEncodingsFile(string const & enc_name,
1128 string const & symbols_name)
1130 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1131 << symbols_name << "...");
1133 FileName const symbols_path = libFileSearch(string(), symbols_name);
1134 if (symbols_path.empty()) {
1135 showFileError(symbols_name);
1139 FileName const enc_path = libFileSearch(string(), enc_name);
1140 if (enc_path.empty()) {
1141 showFileError(enc_name);
1144 encodings.read(enc_path, symbols_path);
1153 /// return the the number of arguments consumed
1154 typedef boost::function<int(string const &, string const &)> cmd_helper;
1156 int parse_dbg(string const & arg, string const &)
1159 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1160 Debug::showTags(lyxerr);
1163 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1165 lyxerr.level(Debug::value(arg));
1166 Debug::showLevel(lyxerr, lyxerr.level());
1171 int parse_help(string const &, string const &)
1174 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1175 "Command line switches (case sensitive):\n"
1176 "\t-help summarize LyX usage\n"
1177 "\t-userdir dir set user directory to dir\n"
1178 "\t-sysdir dir set system directory to dir\n"
1179 "\t-geometry WxH+X+Y set geometry of the main window\n"
1180 "\t-dbg feature[,feature]...\n"
1181 " select the features to debug.\n"
1182 " Type `lyx -dbg' to see the list of features\n"
1183 "\t-x [--execute] command\n"
1184 " where command is a lyx command.\n"
1185 "\t-e [--export] fmt\n"
1186 " where fmt is the export format of choice.\n"
1187 " Look on Tools->Preferences->File formats->Format\n"
1188 " to get an idea which parameters should be passed.\n"
1189 "\t-i [--import] fmt file.xxx\n"
1190 " where fmt is the import format of choice\n"
1191 " and file.xxx is the file to be imported.\n"
1192 "\t-version summarize version and build info\n"
1193 "Check the LyX man page for more details.")) << endl;
1199 int parse_version(string const &, string const &)
1201 lyxerr << "LyX " << lyx_version
1202 << " (" << lyx_release_date << ")" << endl;
1203 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1205 lyxerr << lyx_version_info << endl;
1211 int parse_sysdir(string const & arg, string const &)
1214 Alert::error(_("No system directory"),
1215 _("Missing directory for -sysdir switch"));
1218 cl_system_support = arg;
1223 int parse_userdir(string const & arg, string const &)
1226 Alert::error(_("No user directory"),
1227 _("Missing directory for -userdir switch"));
1230 cl_user_support = arg;
1235 int parse_execute(string const & arg, string const &)
1238 Alert::error(_("Incomplete command"),
1239 _("Missing command string after --execute switch"));
1247 int parse_export(string const & type, string const &)
1250 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1251 "--export switch")) << endl;
1254 batch = "buffer-export " + type;
1260 int parse_import(string const & type, string const & file)
1263 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1264 "--import switch")) << endl;
1268 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1272 batch = "buffer-import " + type + ' ' + file;
1277 int parse_geometry(string const & arg1, string const &)
1280 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1281 // remove also the arg
1284 // don't remove "-geometry"
1293 void LyX::easyParse(int & argc, char * argv[])
1295 map<string, cmd_helper> cmdmap;
1297 cmdmap["-dbg"] = parse_dbg;
1298 cmdmap["-help"] = parse_help;
1299 cmdmap["--help"] = parse_help;
1300 cmdmap["-version"] = parse_version;
1301 cmdmap["--version"] = parse_version;
1302 cmdmap["-sysdir"] = parse_sysdir;
1303 cmdmap["-userdir"] = parse_userdir;
1304 cmdmap["-x"] = parse_execute;
1305 cmdmap["--execute"] = parse_execute;
1306 cmdmap["-e"] = parse_export;
1307 cmdmap["--export"] = parse_export;
1308 cmdmap["-i"] = parse_import;
1309 cmdmap["--import"] = parse_import;
1310 cmdmap["-geometry"] = parse_geometry;
1312 for (int i = 1; i < argc; ++i) {
1313 map<string, cmd_helper>::const_iterator it
1314 = cmdmap.find(argv[i]);
1316 // don't complain if not found - may be parsed later
1317 if (it == cmdmap.end())
1321 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1323 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1325 int const remove = 1 + it->second(arg, arg2);
1327 // Now, remove used arguments by shifting
1328 // the following ones remove places down.
1331 for (int j = i; j < argc; ++j)
1332 argv[j] = argv[j + remove];
1337 pimpl_->batch_command = batch;
1341 FuncStatus getStatus(FuncRequest const & action)
1343 return LyX::ref().lyxFunc().getStatus(action);
1347 void dispatch(FuncRequest const & action)
1349 LyX::ref().lyxFunc().dispatch(action);
1353 BufferList & theBufferList()
1355 return LyX::ref().bufferList();
1359 LyXFunc & theLyXFunc()
1361 return LyX::ref().lyxFunc();
1365 Server & theServer()
1367 // FIXME: this should not be use_gui dependent
1368 BOOST_ASSERT(use_gui);
1369 return LyX::ref().server();
1373 ServerSocket & theServerSocket()
1375 // FIXME: this should not be use_gui dependent
1376 BOOST_ASSERT(use_gui);
1377 return LyX::ref().socket();
1381 KeyMap & theTopLevelKeymap()
1383 return LyX::ref().topLevelKeymap();
1387 Converters & theConverters()
1389 return LyX::ref().converters();
1393 Converters & theSystemConverters()
1395 return LyX::ref().systemConverters();
1399 Movers & theMovers()
1401 return LyX::ref().pimpl_->movers_;
1405 Mover const & getMover(string const & fmt)
1407 return LyX::ref().pimpl_->movers_(fmt);
1411 void setMover(string const & fmt, string const & command)
1413 LyX::ref().pimpl_->movers_.set(fmt, command);
1417 Movers & theSystemMovers()
1419 return LyX::ref().pimpl_->system_movers_;
1423 Messages & getMessages(string const & language)
1425 return LyX::ref().getMessages(language);
1429 Messages & getGuiMessages()
1431 return LyX::ref().getGuiMessages();