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 "ConverterCache.h"
23 #include "buffer_funcs.h"
24 #include "BufferList.h"
25 #include "Converter.h"
26 #include "CutAndPaste.h"
29 #include "ErrorList.h"
36 #include "LyXAction.h"
40 #include "ModuleList.h"
42 #include "ServerSocket.h"
43 #include "TextClassList.h"
44 #include "MenuBackend.h"
47 #include "ToolbarBackend.h"
49 #include "frontends/alert.h"
50 #include "frontends/Application.h"
52 #include "support/environment.h"
53 #include "support/filetools.h"
54 #include "support/lstrings.h"
55 #include "support/lyxlib.h"
56 #include "support/ExceptionMessage.h"
57 #include "support/os.h"
58 #include "support/Package.h"
59 #include "support/Path.h"
60 #include "support/Systemcall.h"
62 #include <boost/bind.hpp>
63 #include <boost/scoped_ptr.hpp>
79 #ifndef CXX_GLOBAL_CSTD
87 using support::addName;
88 using support::addPath;
89 using support::bformat;
90 using support::changeExtension;
91 using support::createLyXTmpDir;
92 using support::FileName;
93 using support::fileSearch;
94 using support::getEnv;
95 using support::i18nLibFileSearch;
96 using support::libFileSearch;
97 using support::package;
98 using support::prependEnvPath;
100 using support::Systemcall;
102 namespace Alert = frontend::Alert;
103 namespace os = support::os;
107 // Are we using the GUI at all? We default to true and this is changed
108 // to false when the export feature is used.
112 bool quitting; // flag, that we are quitting the program
116 // Filled with the command line arguments "foo" of "-sysdir foo" or
118 string cl_system_support;
119 string cl_user_support;
121 std::string geometryArg;
123 LyX * singleton_ = 0;
125 void showFileError(string const & error)
127 Alert::warning(_("Could not read configuration file"),
128 bformat(_("Error while reading the configuration file\n%1$s.\n"
129 "Please check your installation."), from_utf8(error)));
133 void reconfigureUserLyXDir()
135 string const configure_command = package().configure_command();
137 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
138 support::PathChanger p(package().user_support());
140 one.startscript(Systemcall::Wait, configure_command);
141 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
147 /// The main application class private implementation.
152 // Set the default User Interface language as soon as possible.
153 // The language used will be derived from the environment
155 messages_["GUI"] = Messages();
157 /// our function handler
160 BufferList buffer_list_;
162 boost::scoped_ptr<KeyMap> toplevel_keymap_;
164 boost::scoped_ptr<CmdDef> toplevel_cmddef_;
166 boost::scoped_ptr<Server> lyx_server_;
168 boost::scoped_ptr<ServerSocket> lyx_socket_;
170 boost::scoped_ptr<frontend::Application> application_;
171 /// lyx session, containing lastfiles, lastfilepos, and lastopened
172 boost::scoped_ptr<Session> session_;
174 /// Files to load at start.
175 vector<FileName> files_to_load_;
177 /// The messages translators.
178 map<string, Messages> messages_;
180 /// The file converters.
181 Converters converters_;
183 // The system converters copy after reading lyxrc.defaults.
184 Converters system_converters_;
189 Movers system_movers_;
191 /// has this user started lyx for the first time?
193 /// the parsed command line batch command if any
194 std::string batch_command;
198 frontend::Application * theApp()
201 return singleton_->pimpl_->application_.get();
215 BOOST_ASSERT(singleton_);
220 LyX const & LyX::cref()
222 BOOST_ASSERT(singleton_);
235 BufferList & LyX::bufferList()
237 return pimpl_->buffer_list_;
241 BufferList const & LyX::bufferList() const
243 return pimpl_->buffer_list_;
247 Session & LyX::session()
249 BOOST_ASSERT(pimpl_->session_.get());
250 return *pimpl_->session_.get();
254 Session const & LyX::session() const
256 BOOST_ASSERT(pimpl_->session_.get());
257 return *pimpl_->session_.get();
261 LyXFunc & LyX::lyxFunc()
263 return pimpl_->lyxfunc_;
267 LyXFunc const & LyX::lyxFunc() const
269 return pimpl_->lyxfunc_;
273 Server & LyX::server()
275 BOOST_ASSERT(pimpl_->lyx_server_.get());
276 return *pimpl_->lyx_server_.get();
280 Server const & LyX::server() const
282 BOOST_ASSERT(pimpl_->lyx_server_.get());
283 return *pimpl_->lyx_server_.get();
287 ServerSocket & LyX::socket()
289 BOOST_ASSERT(pimpl_->lyx_socket_.get());
290 return *pimpl_->lyx_socket_.get();
294 ServerSocket const & LyX::socket() const
296 BOOST_ASSERT(pimpl_->lyx_socket_.get());
297 return *pimpl_->lyx_socket_.get();
301 frontend::Application & LyX::application()
303 BOOST_ASSERT(pimpl_->application_.get());
304 return *pimpl_->application_.get();
308 frontend::Application const & LyX::application() const
310 BOOST_ASSERT(pimpl_->application_.get());
311 return *pimpl_->application_.get();
315 KeyMap & LyX::topLevelKeymap()
317 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
318 return *pimpl_->toplevel_keymap_.get();
322 CmdDef & LyX::topLevelCmdDef()
324 BOOST_ASSERT(pimpl_->toplevel_cmddef_.get());
325 return *pimpl_->toplevel_cmddef_.get();
329 Converters & LyX::converters()
331 return pimpl_->converters_;
335 Converters & LyX::systemConverters()
337 return pimpl_->system_converters_;
341 KeyMap const & LyX::topLevelKeymap() const
343 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
344 return *pimpl_->toplevel_keymap_.get();
348 Messages & LyX::getMessages(std::string const & language)
350 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
352 if (it != pimpl_->messages_.end())
355 std::pair<map<string, Messages>::iterator, bool> result =
356 pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
358 BOOST_ASSERT(result.second);
359 return result.first->second;
363 Messages & LyX::getGuiMessages()
365 return pimpl_->messages_["GUI"];
369 void LyX::setGuiLanguage(std::string const & language)
371 pimpl_->messages_["GUI"] = Messages(language);
375 int LyX::exec(int & argc, char * argv[])
377 // Here we need to parse the command line. At least
378 // we need to parse for "-dbg" and "-help"
379 easyParse(argc, argv);
382 support::init_package(to_utf8(from_local8bit(argv[0])),
383 cl_system_support, cl_user_support,
384 support::top_build_dir_is_one_level_up);
385 } catch (support::ExceptionMessage const & message) {
386 if (message.type_ == support::ErrorException) {
387 Alert::error(message.title_, message.details_);
389 } else if (message.type_ == support::WarningException) {
390 Alert::warning(message.title_, message.details_);
394 // Reinit the messages machinery in case package() knows
395 // something interesting about the locale directory.
399 // FIXME: create a ConsoleApplication
400 int exit_status = init(argc, argv);
408 if (pimpl_->batch_command.empty() || pimpl_->buffer_list_.empty()) {
413 BufferList::iterator begin = pimpl_->buffer_list_.begin();
415 bool final_success = false;
416 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
418 if (buf != buf->masterBuffer())
420 bool success = false;
421 buf->dispatch(pimpl_->batch_command, &success);
422 final_success |= success;
425 return !final_success;
428 // Let the frontend parse and remove all arguments that it knows
429 pimpl_->application_.reset(createApplication(argc, argv));
431 // Parse and remove all known arguments in the LyX singleton
432 // Give an error for all remaining ones.
433 int exit_status = init(argc, argv);
435 // Kill the application object before exiting.
436 pimpl_->application_.reset();
443 /* Create a CoreApplication class that will provide the main event loop
444 * and the socket callback registering. With Qt4, only QtCore
445 * library would be needed.
446 * When this is done, a server_mode could be created and the following two
447 * line would be moved out from here.
449 // Note: socket callback must be registered after init(argc, argv)
450 // such that package().temp_dir() is properly initialized.
451 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
452 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
453 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
455 // Start the real execution loop.
456 exit_status = pimpl_->application_->exec();
464 void LyX::prepareExit()
466 // Clear the clipboard and selection stack:
467 cap::clearCutStack();
468 cap::clearSelection();
470 // Set a flag that we do quitting from the program,
471 // so no refreshes are necessary.
474 // close buffers first
475 pimpl_->buffer_list_.closeAll();
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);
491 if (pimpl_->session_)
492 pimpl_->session_->writeFile();
493 pimpl_->session_.reset();
494 pimpl_->lyx_server_.reset();
495 pimpl_->lyx_socket_.reset();
498 // Kill the application object before exiting. This avoids crashes
499 // when exiting on Linux.
500 if (pimpl_->application_)
501 pimpl_->application_.reset();
505 void LyX::earlyExit(int status)
507 BOOST_ASSERT(pimpl_->application_.get());
508 // LyX::pimpl_::application_ is not initialised at this
509 // point so it's safe to just exit after some cleanup.
515 int LyX::init(int & argc, char * argv[])
517 // check for any spurious extra arguments
518 // other than documents
519 for (int argi = 1; argi < argc ; ++argi) {
520 if (argv[argi][0] == '-') {
522 bformat(_("Wrong command line option `%1$s'. Exiting."),
523 from_utf8(argv[argi]))) << endl;
528 // Initialization of LyX (reads lyxrc and more)
529 LYXERR(Debug::INIT, "Initializing LyX::init...");
530 bool success = init();
531 LYXERR(Debug::INIT, "Initializing LyX::init...done");
535 for (int argi = argc - 1; argi >= 1; --argi) {
536 // get absolute path of file and add ".lyx" to
537 // the filename if necessary
538 pimpl_->files_to_load_.push_back(fileSearch(string(),
539 os::internal_path(to_utf8(from_local8bit(argv[argi]))),
540 "lyx", support::allow_unreadable));
544 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
550 void LyX::addFileToLoad(FileName const & fname)
552 vector<FileName>::const_iterator cit = std::find(
553 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
556 if (cit == pimpl_->files_to_load_.end())
557 pimpl_->files_to_load_.push_back(fname);
561 void LyX::loadFiles()
563 vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
564 vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
566 for (; it != end; ++it) {
570 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
571 if (buf->loadLyXFile(*it)) {
572 ErrorList const & el = buf->errorList("Parse");
574 for_each(el.begin(), el.end(),
575 boost::bind(&LyX::printError, this, _1));
578 pimpl_->buffer_list_.release(buf);
583 void LyX::execBatchCommands()
585 // The advantage of doing this here is that the event loop
586 // is already started. So any need for interaction will be
590 // if reconfiguration is needed.
591 if (textclasslist.empty()) {
592 switch (Alert::prompt(
593 _("No textclass is found"),
594 _("LyX cannot continue because no textclass is found. "
595 "You can either reconfigure normally, or reconfigure using "
596 "default textclasses, or quit LyX."),
603 // regular reconfigure
604 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
607 // reconfigure --without-latex-config
608 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
609 " --without-latex-config"));
612 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
616 // Execute batch commands if available
617 if (pimpl_->batch_command.empty())
620 LYXERR(Debug::INIT, "About to handle -x '" << pimpl_->batch_command << '\'');
622 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
626 void LyX::restoreGuiSession()
628 // create the main window
629 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
631 // if there is no valid class list, do not load any file.
632 if (textclasslist.empty())
635 // if some files were specified at command-line we assume that the
636 // user wants to edit *these* files and not to restore the session.
637 if (!pimpl_->files_to_load_.empty()) {
638 for_each(pimpl_->files_to_load_.begin(),
639 pimpl_->files_to_load_.end(),
640 bind(&LyXFunc::loadAndViewFile, pimpl_->lyxfunc_, _1, true));
641 // clear this list to save a few bytes of RAM
642 pimpl_->files_to_load_.clear();
643 pimpl_->session_->lastOpened().clear();
645 } else if (lyxrc.load_session) {
646 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
647 // do not add to the lastfile list since these files are restored from
648 // last session, and should be already there (regular files), or should
649 // not be added at all (help files).
650 for_each(lastopened.begin(), lastopened.end(),
651 bind(&LyXFunc::loadAndViewFile, pimpl_->lyxfunc_, _1, false));
653 // clear this list to save a few bytes of RAM
654 pimpl_->session_->lastOpened().clear();
657 BufferList::iterator I = pimpl_->buffer_list_.begin();
658 BufferList::iterator end = pimpl_->buffer_list_.end();
659 for (; I != end; ++I) {
661 if (buf != buf->masterBuffer())
670 The SIGHUP signal does not exist on Windows and does not need to be handled.
672 Windows handles SIGFPE and SIGSEGV signals as expected.
674 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
675 cause a new thread to be spawned. This may well result in unexpected
676 behaviour by the single-threaded LyX.
678 SIGTERM signals will come only from another process actually sending
679 that signal using 'raise' in Windows' POSIX compatability layer. It will
680 not come from the general "terminate process" methods that everyone
681 actually uses (and which can't be trapped). Killing an app 'politely' on
682 Windows involves first sending a WM_CLOSE message, something that is
683 caught already by the Qt frontend.
685 For more information see:
687 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
688 ...signals are mostly useless on Windows for a variety of reasons that are
691 'UNIX Application Migration Guide, Chapter 9'
692 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
694 'How To Terminate an Application "Cleanly" in Win32'
695 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
699 static void error_handler(int err_sig)
701 // Throw away any signals other than the first one received.
702 static sig_atomic_t handling_error = false;
705 handling_error = true;
707 // We have received a signal indicating a fatal error, so
708 // try and save the data ASAP.
709 LyX::cref().emergencyCleanup();
711 // These lyxerr calls may or may not work:
713 // Signals are asynchronous, so the main program may be in a very
714 // fragile state when a signal is processed and thus while a signal
715 // handler function executes.
716 // In general, therefore, we should avoid performing any
717 // I/O operations or calling most library and system functions from
720 // This shouldn't matter here, however, as we've already invoked
725 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
729 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
732 lyxerr << "\nlyx: SIGSEGV signal caught\n"
733 "Sorry, you have found a bug in LyX. "
734 "Please read the bug-reporting instructions "
735 "in Help->Introduction and send us a bug report, "
736 "if necessary. Thanks !\nBye." << endl;
744 // Deinstall the signal handlers
746 signal(SIGHUP, SIG_DFL);
748 signal(SIGINT, SIG_DFL);
749 signal(SIGFPE, SIG_DFL);
750 signal(SIGSEGV, SIG_DFL);
751 signal(SIGTERM, SIG_DFL);
754 if (err_sig == SIGSEGV ||
755 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
757 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
766 void LyX::printError(ErrorItem const & ei)
768 docstring tmp = _("LyX: ") + ei.error + char_type(':')
770 std::cerr << to_utf8(tmp) << std::endl;
777 signal(SIGHUP, error_handler);
779 signal(SIGFPE, error_handler);
780 signal(SIGSEGV, error_handler);
781 signal(SIGINT, error_handler);
782 signal(SIGTERM, error_handler);
783 // SIGPIPE can be safely ignored.
785 lyxrc.tempdir_path = package().temp_dir().absFilename();
786 lyxrc.document_path = package().document_dir().absFilename();
788 if (lyxrc.template_path.empty()) {
789 lyxrc.template_path = addPath(package().system_support().absFilename(),
794 // Read configuration files
797 // This one may have been distributed along with LyX.
798 if (!readRcFile("lyxrc.dist"))
801 // Set the language defined by the distributor.
802 //setGuiLanguage(lyxrc.gui_language);
804 // Set the PATH correctly.
805 #if !defined (USE_POSIX_PACKAGING)
806 // Add the directory containing the LyX executable to the path
807 // so that LyX can find things like tex2lyx.
808 if (package().build_support().empty())
809 prependEnvPath("PATH", package().binary_dir().absFilename());
811 if (!lyxrc.path_prefix.empty())
812 prependEnvPath("PATH", lyxrc.path_prefix);
814 // Check that user LyX directory is ok.
815 if (queryUserLyXDir(package().explicit_user_support()))
816 reconfigureUserLyXDir();
818 // no need for a splash when there is no GUI
823 // This one is generated in user_support directory by lib/configure.py.
824 if (!readRcFile("lyxrc.defaults"))
827 // Query the OS to know what formats are viewed natively
828 formats.setAutoOpen();
830 // Read lyxrc.dist again to be able to override viewer auto-detection.
831 readRcFile("lyxrc.dist");
833 system_lyxrc = lyxrc;
834 system_formats = formats;
835 pimpl_->system_converters_ = pimpl_->converters_;
836 pimpl_->system_movers_ = pimpl_->movers_;
837 system_lcolor = lcolor;
839 // This one is edited through the preferences dialog.
840 if (!readRcFile("preferences"))
843 if (!readEncodingsFile("encodings", "unicodesymbols"))
845 if (!readLanguagesFile("languages"))
849 LYXERR(Debug::INIT, "Reading layouts...");
855 // read keymap and ui files in batch mode as well
856 // because InsetInfo needs to know these to produce
857 // the correct output
859 // Set the language defined by the user.
860 //setGuiLanguage(lyxrc.gui_language);
862 // Set up command definitions
863 pimpl_->toplevel_cmddef_.reset(new CmdDef);
864 pimpl_->toplevel_cmddef_->read(lyxrc.def_file);
867 pimpl_->toplevel_keymap_.reset(new KeyMap);
868 pimpl_->toplevel_keymap_->read("site");
869 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
870 // load user bind file user.bind
871 pimpl_->toplevel_keymap_->read("user");
873 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
876 if (!readUIFile(lyxrc.ui_file))
879 if (lyxerr.debugging(Debug::LYXRC))
882 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
883 if (!lyxrc.path_prefix.empty())
884 prependEnvPath("PATH", lyxrc.path_prefix);
886 FileName const document_path(lyxrc.document_path);
887 if (document_path.exists() && document_path.isDirectory())
888 package().document_dir() = document_path;
890 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
891 if (package().temp_dir().empty()) {
892 Alert::error(_("Could not create temporary directory"),
893 bformat(_("Could not create a temporary directory in\n"
894 "%1$s. Make sure that this\n"
895 "path exists and is writable and try again."),
896 from_utf8(lyxrc.tempdir_path)));
897 // createLyXTmpDir() tries sufficiently hard to create a
898 // usable temp dir, so the probability to come here is
899 // close to zero. We therefore don't try to overcome this
900 // problem with e.g. asking the user for a new path and
901 // trying again but simply exit.
905 LYXERR(Debug::INIT, "LyX tmp dir: `"
906 << package().temp_dir().absFilename() << '\'');
908 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
909 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
911 // This must happen after package initialization and after lyxrc is
912 // read, therefore it can't be done by a static object.
913 ConverterCache::init();
919 void LyX::emergencyCleanup() const
921 // what to do about tmpfiles is non-obvious. we would
922 // like to delete any we find, but our lyxdir might
923 // contain documents etc. which might be helpful on
926 pimpl_->buffer_list_.emergencyWriteAll();
928 if (pimpl_->lyx_server_)
929 pimpl_->lyx_server_->emergencyCleanup();
930 pimpl_->lyx_server_.reset();
931 pimpl_->lyx_socket_.reset();
936 void LyX::deadKeyBindings(KeyMap * kbmap)
938 // bindKeyings for transparent handling of deadkeys
939 // The keysyms are gotten from XFree86 X11R6
940 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
941 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
942 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
943 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
944 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
945 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
946 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
947 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
948 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
949 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
950 // nothing with this name
951 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
952 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
953 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
954 // nothing with this name either...
955 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
956 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
957 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
958 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
962 // return true if file does not exist or is older than configure.py.
963 static bool needsUpdate(string const & file)
965 // We cannot initialize configure_script directly because the package
966 // is not initialized yet when static objects are constructed.
967 static FileName configure_script;
968 static bool firstrun = true;
971 FileName(addName(package().system_support().absFilename(),
977 FileName(addName(package().user_support().absFilename(), file));
978 return !absfile.exists()
979 || configure_script.lastModified() > absfile.lastModified();
983 bool LyX::queryUserLyXDir(bool explicit_userdir)
985 // Does user directory exist?
986 FileName const sup = package().user_support();
987 if (sup.exists() && sup.isDirectory()) {
990 return needsUpdate("lyxrc.defaults")
991 || needsUpdate("lyxmodules.lst")
992 || needsUpdate("textclass.lst")
993 || needsUpdate("packages.lst");
996 first_start = !explicit_userdir;
998 // If the user specified explicitly a directory, ask whether
999 // to create it. If the user says "no", then exit.
1000 if (explicit_userdir &&
1002 _("Missing user LyX directory"),
1003 bformat(_("You have specified a non-existent user "
1004 "LyX directory, %1$s.\n"
1005 "It is needed to keep your own configuration."),
1006 from_utf8(package().user_support().absFilename())),
1008 _("&Create directory"),
1010 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1011 earlyExit(EXIT_FAILURE);
1014 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1015 from_utf8(sup.absFilename()))) << endl;
1017 if (!sup.createDirectory(0755)) {
1018 // Failed, so let's exit.
1019 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1021 earlyExit(EXIT_FAILURE);
1028 bool LyX::readRcFile(string const & name)
1030 LYXERR(Debug::INIT, "About to read " << name << "... ");
1032 FileName const lyxrc_path = libFileSearch(string(), name);
1033 if (!lyxrc_path.empty()) {
1034 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
1035 if (lyxrc.read(lyxrc_path) < 0) {
1036 showFileError(name);
1040 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
1046 // Read the ui file `name'
1047 bool LyX::readUIFile(string const & name, bool include)
1057 struct keyword_item uitags[ui_last - 1] = {
1058 { "include", ui_include },
1059 { "menuset", ui_menuset },
1060 { "toolbars", ui_toolbars },
1061 { "toolbarset", ui_toolbarset }
1064 // Ensure that a file is read only once (prevents include loops)
1065 static std::list<string> uifiles;
1066 std::list<string>::const_iterator it = uifiles.begin();
1067 std::list<string>::const_iterator end = uifiles.end();
1068 it = std::find(it, end, name);
1070 LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1071 << "Is this an include loop?");
1075 LYXERR(Debug::INIT, "About to read " << name << "...");
1080 ui_path = libFileSearch("ui", name, "inc");
1081 if (ui_path.empty())
1082 ui_path = libFileSearch("ui",
1083 changeExtension(name, "inc"));
1086 ui_path = libFileSearch("ui", name, "ui");
1088 if (ui_path.empty()) {
1089 LYXERR(Debug::INIT, "Could not find " << name);
1090 showFileError(name);
1094 uifiles.push_back(name);
1096 LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1097 Lexer lex(uitags, ui_last - 1);
1098 lex.setFile(ui_path);
1100 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1104 if (lyxerr.debugging(Debug::PARSER))
1105 lex.printTable(lyxerr);
1107 while (lex.isOK()) {
1108 switch (lex.lex()) {
1111 string const file = lex.getString();
1112 if (!readUIFile(file, true))
1117 menubackend.read(lex);
1121 toolbarbackend.readToolbars(lex);
1125 toolbarbackend.readToolbarSettings(lex);
1129 if (!rtrim(lex.getString()).empty())
1130 lex.printError("LyX::ReadUIFile: "
1131 "Unknown menu tag: `$$Token'");
1139 // Read the languages file `name'
1140 bool LyX::readLanguagesFile(string const & name)
1142 LYXERR(Debug::INIT, "About to read " << name << "...");
1144 FileName const lang_path = libFileSearch(string(), name);
1145 if (lang_path.empty()) {
1146 showFileError(name);
1149 languages.read(lang_path);
1154 // Read the encodings file `name'
1155 bool LyX::readEncodingsFile(string const & enc_name,
1156 string const & symbols_name)
1158 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1159 << symbols_name << "...");
1161 FileName const symbols_path = libFileSearch(string(), symbols_name);
1162 if (symbols_path.empty()) {
1163 showFileError(symbols_name);
1167 FileName const enc_path = libFileSearch(string(), enc_name);
1168 if (enc_path.empty()) {
1169 showFileError(enc_name);
1172 encodings.read(enc_path, symbols_path);
1181 /// return the the number of arguments consumed
1182 typedef boost::function<int(string const &, string const &)> cmd_helper;
1184 int parse_dbg(string const & arg, string const &)
1187 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1188 Debug::showTags(lyxerr);
1191 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1193 lyxerr.level(Debug::value(arg));
1194 Debug::showLevel(lyxerr, lyxerr.level());
1199 int parse_help(string const &, string const &)
1202 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1203 "Command line switches (case sensitive):\n"
1204 "\t-help summarize LyX usage\n"
1205 "\t-userdir dir set user directory to dir\n"
1206 "\t-sysdir dir set system directory to dir\n"
1207 "\t-geometry WxH+X+Y set geometry of the main window\n"
1208 "\t-dbg feature[,feature]...\n"
1209 " select the features to debug.\n"
1210 " Type `lyx -dbg' to see the list of features\n"
1211 "\t-x [--execute] command\n"
1212 " where command is a lyx command.\n"
1213 "\t-e [--export] fmt\n"
1214 " where fmt is the export format of choice.\n"
1215 " Look on Tools->Preferences->File formats->Format\n"
1216 " to get an idea which parameters should be passed.\n"
1217 "\t-i [--import] fmt file.xxx\n"
1218 " where fmt is the import format of choice\n"
1219 " and file.xxx is the file to be imported.\n"
1220 "\t-version summarize version and build info\n"
1221 "Check the LyX man page for more details.")) << endl;
1227 int parse_version(string const &, string const &)
1229 lyxerr << "LyX " << lyx_version
1230 << " (" << lyx_release_date << ")" << endl;
1231 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1233 lyxerr << lyx_version_info << endl;
1239 int parse_sysdir(string const & arg, string const &)
1242 Alert::error(_("No system directory"),
1243 _("Missing directory for -sysdir switch"));
1246 cl_system_support = arg;
1251 int parse_userdir(string const & arg, string const &)
1254 Alert::error(_("No user directory"),
1255 _("Missing directory for -userdir switch"));
1258 cl_user_support = arg;
1263 int parse_execute(string const & arg, string const &)
1266 Alert::error(_("Incomplete command"),
1267 _("Missing command string after --execute switch"));
1275 int parse_export(string const & type, string const &)
1278 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1279 "--export switch")) << endl;
1282 batch = "buffer-export " + type;
1288 int parse_import(string const & type, string const & file)
1291 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1292 "--import switch")) << endl;
1296 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1300 batch = "buffer-import " + type + ' ' + file;
1305 int parse_geometry(string const & arg1, string const &)
1308 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1309 // remove also the arg
1312 // don't remove "-geometry"
1321 void LyX::easyParse(int & argc, char * argv[])
1323 std::map<string, cmd_helper> cmdmap;
1325 cmdmap["-dbg"] = parse_dbg;
1326 cmdmap["-help"] = parse_help;
1327 cmdmap["--help"] = parse_help;
1328 cmdmap["-version"] = parse_version;
1329 cmdmap["--version"] = parse_version;
1330 cmdmap["-sysdir"] = parse_sysdir;
1331 cmdmap["-userdir"] = parse_userdir;
1332 cmdmap["-x"] = parse_execute;
1333 cmdmap["--execute"] = parse_execute;
1334 cmdmap["-e"] = parse_export;
1335 cmdmap["--export"] = parse_export;
1336 cmdmap["-i"] = parse_import;
1337 cmdmap["--import"] = parse_import;
1338 cmdmap["-geometry"] = parse_geometry;
1340 for (int i = 1; i < argc; ++i) {
1341 std::map<string, cmd_helper>::const_iterator it
1342 = cmdmap.find(argv[i]);
1344 // don't complain if not found - may be parsed later
1345 if (it == cmdmap.end())
1349 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1351 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1353 int const remove = 1 + it->second(arg, arg2);
1355 // Now, remove used arguments by shifting
1356 // the following ones remove places down.
1359 for (int j = i; j < argc; ++j)
1360 argv[j] = argv[j + remove];
1365 pimpl_->batch_command = batch;
1369 FuncStatus getStatus(FuncRequest const & action)
1371 return LyX::ref().lyxFunc().getStatus(action);
1375 void dispatch(FuncRequest const & action)
1377 LyX::ref().lyxFunc().dispatch(action);
1381 BufferList & theBufferList()
1383 return LyX::ref().bufferList();
1387 LyXFunc & theLyXFunc()
1389 return LyX::ref().lyxFunc();
1393 Server & theServer()
1395 // FIXME: this should not be use_gui dependent
1396 BOOST_ASSERT(use_gui);
1397 return LyX::ref().server();
1401 ServerSocket & theServerSocket()
1403 // FIXME: this should not be use_gui dependent
1404 BOOST_ASSERT(use_gui);
1405 return LyX::ref().socket();
1409 KeyMap & theTopLevelKeymap()
1411 return LyX::ref().topLevelKeymap();
1415 Converters & theConverters()
1417 return LyX::ref().converters();
1421 Converters & theSystemConverters()
1423 return LyX::ref().systemConverters();
1427 Movers & theMovers()
1429 return LyX::ref().pimpl_->movers_;
1433 Mover const & getMover(std::string const & fmt)
1435 return LyX::ref().pimpl_->movers_(fmt);
1439 void setMover(std::string const & fmt, std::string const & command)
1441 LyX::ref().pimpl_->movers_.set(fmt, command);
1445 Movers & theSystemMovers()
1447 return LyX::ref().pimpl_->system_movers_;
1451 Messages & getMessages(std::string const & language)
1453 return LyX::ref().getMessages(language);
1457 Messages & getGuiMessages()
1459 return LyX::ref().getGuiMessages();