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"
51 #include "frontends/LyXView.h"
53 #include "support/environment.h"
54 #include "support/filetools.h"
55 #include "support/lstrings.h"
56 #include "support/lyxlib.h"
57 #include "support/ExceptionMessage.h"
58 #include "support/os.h"
59 #include "support/Package.h"
60 #include "support/Path.h"
61 #include "support/Systemcall.h"
63 #include <boost/bind.hpp>
64 #include <boost/scoped_ptr.hpp>
80 #ifndef CXX_GLOBAL_CSTD
88 using support::addName;
89 using support::addPath;
90 using support::bformat;
91 using support::changeExtension;
92 using support::createLyXTmpDir;
93 using support::FileName;
94 using support::fileSearch;
95 using support::getEnv;
96 using support::i18nLibFileSearch;
97 using support::libFileSearch;
98 using support::package;
99 using support::prependEnvPath;
100 using support::rtrim;
101 using support::Systemcall;
102 using frontend::LyXView;
104 namespace Alert = frontend::Alert;
105 namespace os = support::os;
109 // Are we using the GUI at all? We default to true and this is changed
110 // to false when the export feature is used.
114 bool quitting; // flag, that we are quitting the program
118 // Filled with the command line arguments "foo" of "-sysdir foo" or
120 string cl_system_support;
121 string cl_user_support;
123 std::string geometryArg;
125 LyX * singleton_ = 0;
127 void showFileError(string const & error)
129 Alert::warning(_("Could not read configuration file"),
130 bformat(_("Error while reading the configuration file\n%1$s.\n"
131 "Please check your installation."), from_utf8(error)));
135 void reconfigureUserLyXDir()
137 string const configure_command = package().configure_command();
139 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
140 support::PathChanger p(package().user_support());
142 one.startscript(Systemcall::Wait, configure_command);
143 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
149 /// The main application class private implementation.
154 // Set the default User Interface language as soon as possible.
155 // The language used will be derived from the environment
157 messages_["GUI"] = Messages();
159 /// our function handler
162 BufferList buffer_list_;
164 boost::scoped_ptr<KeyMap> toplevel_keymap_;
166 boost::scoped_ptr<CmdDef> toplevel_cmddef_;
168 boost::scoped_ptr<Server> lyx_server_;
170 boost::scoped_ptr<ServerSocket> lyx_socket_;
172 boost::scoped_ptr<frontend::Application> application_;
173 /// lyx session, containing lastfiles, lastfilepos, and lastopened
174 boost::scoped_ptr<Session> session_;
176 /// Files to load at start.
177 vector<FileName> files_to_load_;
179 /// The messages translators.
180 map<string, Messages> messages_;
182 /// The file converters.
183 Converters converters_;
185 // The system converters copy after reading lyxrc.defaults.
186 Converters system_converters_;
191 Movers system_movers_;
193 /// has this user started lyx for the first time?
195 /// the parsed command line batch command if any
196 std::string batch_command;
200 frontend::Application * theApp()
203 return singleton_->pimpl_->application_.get();
217 BOOST_ASSERT(singleton_);
222 LyX const & LyX::cref()
224 BOOST_ASSERT(singleton_);
237 BufferList & LyX::bufferList()
239 return pimpl_->buffer_list_;
243 BufferList const & LyX::bufferList() const
245 return pimpl_->buffer_list_;
249 Session & LyX::session()
251 BOOST_ASSERT(pimpl_->session_.get());
252 return *pimpl_->session_.get();
256 Session const & LyX::session() const
258 BOOST_ASSERT(pimpl_->session_.get());
259 return *pimpl_->session_.get();
263 LyXFunc & LyX::lyxFunc()
265 return pimpl_->lyxfunc_;
269 LyXFunc const & LyX::lyxFunc() const
271 return pimpl_->lyxfunc_;
275 Server & LyX::server()
277 BOOST_ASSERT(pimpl_->lyx_server_.get());
278 return *pimpl_->lyx_server_.get();
282 Server const & LyX::server() const
284 BOOST_ASSERT(pimpl_->lyx_server_.get());
285 return *pimpl_->lyx_server_.get();
289 ServerSocket & LyX::socket()
291 BOOST_ASSERT(pimpl_->lyx_socket_.get());
292 return *pimpl_->lyx_socket_.get();
296 ServerSocket const & LyX::socket() const
298 BOOST_ASSERT(pimpl_->lyx_socket_.get());
299 return *pimpl_->lyx_socket_.get();
303 frontend::Application & LyX::application()
305 BOOST_ASSERT(pimpl_->application_.get());
306 return *pimpl_->application_.get();
310 frontend::Application const & LyX::application() const
312 BOOST_ASSERT(pimpl_->application_.get());
313 return *pimpl_->application_.get();
317 KeyMap & LyX::topLevelKeymap()
319 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
320 return *pimpl_->toplevel_keymap_.get();
324 CmdDef & LyX::topLevelCmdDef()
326 BOOST_ASSERT(pimpl_->toplevel_cmddef_.get());
327 return *pimpl_->toplevel_cmddef_.get();
331 Converters & LyX::converters()
333 return pimpl_->converters_;
337 Converters & LyX::systemConverters()
339 return pimpl_->system_converters_;
343 KeyMap const & LyX::topLevelKeymap() const
345 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
346 return *pimpl_->toplevel_keymap_.get();
350 Messages & LyX::getMessages(std::string const & language)
352 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
354 if (it != pimpl_->messages_.end())
357 std::pair<map<string, Messages>::iterator, bool> result =
358 pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
360 BOOST_ASSERT(result.second);
361 return result.first->second;
365 Messages & LyX::getGuiMessages()
367 return pimpl_->messages_["GUI"];
371 void LyX::setGuiLanguage(std::string const & language)
373 pimpl_->messages_["GUI"] = Messages(language);
377 int LyX::exec(int & argc, char * argv[])
379 // Here we need to parse the command line. At least
380 // we need to parse for "-dbg" and "-help"
381 easyParse(argc, argv);
384 support::init_package(to_utf8(from_local8bit(argv[0])),
385 cl_system_support, cl_user_support,
386 support::top_build_dir_is_one_level_up);
387 } catch (support::ExceptionMessage const & message) {
388 if (message.type_ == support::ErrorException) {
389 Alert::error(message.title_, message.details_);
391 } else if (message.type_ == support::WarningException) {
392 Alert::warning(message.title_, message.details_);
396 // Reinit the messages machinery in case package() knows
397 // something interesting about the locale directory.
401 // FIXME: create a ConsoleApplication
402 int exit_status = init(argc, argv);
410 if (pimpl_->batch_command.empty() || pimpl_->buffer_list_.empty()) {
415 BufferList::iterator begin = pimpl_->buffer_list_.begin();
417 bool final_success = false;
418 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
420 if (buf != buf->masterBuffer())
422 bool success = false;
423 buf->dispatch(pimpl_->batch_command, &success);
424 final_success |= success;
427 return !final_success;
430 // Let the frontend parse and remove all arguments that it knows
431 pimpl_->application_.reset(createApplication(argc, argv));
433 // Parse and remove all known arguments in the LyX singleton
434 // Give an error for all remaining ones.
435 int exit_status = init(argc, argv);
437 // Kill the application object before exiting.
438 pimpl_->application_.reset();
445 /* Create a CoreApplication class that will provide the main event loop
446 * and the socket callback registering. With Qt4, only QtCore
447 * library would be needed.
448 * When this is done, a server_mode could be created and the following two
449 * line would be moved out from here.
451 // Note: socket callback must be registered after init(argc, argv)
452 // such that package().temp_dir() is properly initialized.
453 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
454 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
455 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
457 // Start the real execution loop.
458 exit_status = pimpl_->application_->exec();
466 void LyX::prepareExit()
468 // Clear the clipboard and selection stack:
469 cap::clearCutStack();
470 cap::clearSelection();
472 // Set a flag that we do quitting from the program,
473 // so no refreshes are necessary.
476 // close buffers first
477 pimpl_->buffer_list_.closeAll();
479 // do any other cleanup procedures now
480 if (package().temp_dir() != package().system_temp_dir()) {
481 LYXERR(Debug::INFO, "Deleting tmp dir "
482 << package().temp_dir().absFilename());
484 if (!package().temp_dir().destroyDirectory()) {
485 docstring const msg =
486 bformat(_("Unable to remove the temporary directory %1$s"),
487 from_utf8(package().temp_dir().absFilename()));
488 Alert::warning(_("Unable to remove temporary directory"), msg);
493 if (pimpl_->session_)
494 pimpl_->session_->writeFile();
495 pimpl_->session_.reset();
496 pimpl_->lyx_server_.reset();
497 pimpl_->lyx_socket_.reset();
500 // Kill the application object before exiting. This avoids crashes
501 // when exiting on Linux.
502 if (pimpl_->application_)
503 pimpl_->application_.reset();
507 void LyX::earlyExit(int status)
509 BOOST_ASSERT(pimpl_->application_.get());
510 // LyX::pimpl_::application_ is not initialised at this
511 // point so it's safe to just exit after some cleanup.
517 int LyX::init(int & argc, char * argv[])
519 // check for any spurious extra arguments
520 // other than documents
521 for (int argi = 1; argi < argc ; ++argi) {
522 if (argv[argi][0] == '-') {
524 bformat(_("Wrong command line option `%1$s'. Exiting."),
525 from_utf8(argv[argi]))) << endl;
530 // Initialization of LyX (reads lyxrc and more)
531 LYXERR(Debug::INIT, "Initializing LyX::init...");
532 bool success = init();
533 LYXERR(Debug::INIT, "Initializing LyX::init...done");
537 for (int argi = argc - 1; argi >= 1; --argi) {
538 // get absolute path of file and add ".lyx" to
539 // the filename if necessary
540 pimpl_->files_to_load_.push_back(fileSearch(string(),
541 os::internal_path(to_utf8(from_local8bit(argv[argi]))),
542 "lyx", support::allow_unreadable));
546 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
552 void LyX::addFileToLoad(FileName const & fname)
554 vector<FileName>::const_iterator cit = std::find(
555 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
558 if (cit == pimpl_->files_to_load_.end())
559 pimpl_->files_to_load_.push_back(fname);
563 void LyX::loadFiles()
565 vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
566 vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
568 for (; it != end; ++it) {
572 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
573 if (buf->loadLyXFile(*it)) {
574 ErrorList const & el = buf->errorList("Parse");
576 for_each(el.begin(), el.end(),
577 boost::bind(&LyX::printError, this, _1));
580 pimpl_->buffer_list_.release(buf);
585 void LyX::execBatchCommands()
587 // The advantage of doing this here is that the event loop
588 // is already started. So any need for interaction will be
592 // if reconfiguration is needed.
593 if (textclasslist.empty()) {
594 switch (Alert::prompt(
595 _("No textclass is found"),
596 _("LyX cannot continue because no textclass is found. "
597 "You can either reconfigure normally, or reconfigure using "
598 "default textclasses, or quit LyX."),
605 // regular reconfigure
606 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
609 // reconfigure --without-latex-config
610 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
611 " --without-latex-config"));
614 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
618 // Execute batch commands if available
619 if (pimpl_->batch_command.empty())
622 LYXERR(Debug::INIT, "About to handle -x '" << pimpl_->batch_command << '\'');
624 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
628 void LyX::restoreGuiSession()
630 LyXView * view = newLyXView();
632 // if there is no valid class list, do not load any file.
633 if (textclasslist.empty())
636 // if some files were specified at command-line we assume that the
637 // user wants to edit *these* files and not to restore the session.
638 if (!pimpl_->files_to_load_.empty()) {
639 for_each(pimpl_->files_to_load_.begin(),
640 pimpl_->files_to_load_.end(),
641 bind(&LyXView::loadLyXFile, view, _1, true));
642 // clear this list to save a few bytes of RAM
643 pimpl_->files_to_load_.clear();
644 pimpl_->session_->lastOpened().clear();
646 } else if (lyxrc.load_session) {
647 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
648 // do not add to the lastfile list since these files are restored from
649 // last session, and should be already there (regular files), or should
650 // not be added at all (help files).
651 for_each(lastopened.begin(), lastopened.end(),
652 bind(&LyXView::loadLyXFile, view, _1, false));
654 // clear this list to save a few bytes of RAM
655 pimpl_->session_->lastOpened().clear();
658 BufferList::iterator I = pimpl_->buffer_list_.begin();
659 BufferList::iterator end = pimpl_->buffer_list_.end();
660 for (; I != end; ++I) {
662 if (buf != buf->masterBuffer())
667 // FIXME: Switch to the last loaded Buffer. This must not be the first one
668 // because the Buffer won't be connected in this case. The correct solution
669 // would be to avoid the manual connection of the current Buffer in LyXView.
670 if (!pimpl_->buffer_list_.empty())
671 view->setBuffer(pimpl_->buffer_list_.last());
675 LyXView * LyX::newLyXView()
680 // create the main window
681 LyXView * view = &pimpl_->application_->createView(geometryArg);
689 The SIGHUP signal does not exist on Windows and does not need to be handled.
691 Windows handles SIGFPE and SIGSEGV signals as expected.
693 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
694 cause a new thread to be spawned. This may well result in unexpected
695 behaviour by the single-threaded LyX.
697 SIGTERM signals will come only from another process actually sending
698 that signal using 'raise' in Windows' POSIX compatability layer. It will
699 not come from the general "terminate process" methods that everyone
700 actually uses (and which can't be trapped). Killing an app 'politely' on
701 Windows involves first sending a WM_CLOSE message, something that is
702 caught already by the Qt frontend.
704 For more information see:
706 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
707 ...signals are mostly useless on Windows for a variety of reasons that are
710 'UNIX Application Migration Guide, Chapter 9'
711 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
713 'How To Terminate an Application "Cleanly" in Win32'
714 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
718 static void error_handler(int err_sig)
720 // Throw away any signals other than the first one received.
721 static sig_atomic_t handling_error = false;
724 handling_error = true;
726 // We have received a signal indicating a fatal error, so
727 // try and save the data ASAP.
728 LyX::cref().emergencyCleanup();
730 // These lyxerr calls may or may not work:
732 // Signals are asynchronous, so the main program may be in a very
733 // fragile state when a signal is processed and thus while a signal
734 // handler function executes.
735 // In general, therefore, we should avoid performing any
736 // I/O operations or calling most library and system functions from
739 // This shouldn't matter here, however, as we've already invoked
744 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
748 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
751 lyxerr << "\nlyx: SIGSEGV signal caught\n"
752 "Sorry, you have found a bug in LyX. "
753 "Please read the bug-reporting instructions "
754 "in Help->Introduction and send us a bug report, "
755 "if necessary. Thanks !\nBye." << endl;
763 // Deinstall the signal handlers
765 signal(SIGHUP, SIG_DFL);
767 signal(SIGINT, SIG_DFL);
768 signal(SIGFPE, SIG_DFL);
769 signal(SIGSEGV, SIG_DFL);
770 signal(SIGTERM, SIG_DFL);
773 if (err_sig == SIGSEGV ||
774 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
776 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
785 void LyX::printError(ErrorItem const & ei)
787 docstring tmp = _("LyX: ") + ei.error + char_type(':')
789 std::cerr << to_utf8(tmp) << std::endl;
796 signal(SIGHUP, error_handler);
798 signal(SIGFPE, error_handler);
799 signal(SIGSEGV, error_handler);
800 signal(SIGINT, error_handler);
801 signal(SIGTERM, error_handler);
802 // SIGPIPE can be safely ignored.
804 lyxrc.tempdir_path = package().temp_dir().absFilename();
805 lyxrc.document_path = package().document_dir().absFilename();
807 if (lyxrc.template_path.empty()) {
808 lyxrc.template_path = addPath(package().system_support().absFilename(),
813 // Read configuration files
816 // This one may have been distributed along with LyX.
817 if (!readRcFile("lyxrc.dist"))
820 // Set the language defined by the distributor.
821 //setGuiLanguage(lyxrc.gui_language);
823 // Set the PATH correctly.
824 #if !defined (USE_POSIX_PACKAGING)
825 // Add the directory containing the LyX executable to the path
826 // so that LyX can find things like tex2lyx.
827 if (package().build_support().empty())
828 prependEnvPath("PATH", package().binary_dir().absFilename());
830 if (!lyxrc.path_prefix.empty())
831 prependEnvPath("PATH", lyxrc.path_prefix);
833 // Check that user LyX directory is ok.
834 if (queryUserLyXDir(package().explicit_user_support()))
835 reconfigureUserLyXDir();
837 // no need for a splash when there is no GUI
842 // This one is generated in user_support directory by lib/configure.py.
843 if (!readRcFile("lyxrc.defaults"))
846 // Query the OS to know what formats are viewed natively
847 formats.setAutoOpen();
849 // Read lyxrc.dist again to be able to override viewer auto-detection.
850 readRcFile("lyxrc.dist");
852 system_lyxrc = lyxrc;
853 system_formats = formats;
854 pimpl_->system_converters_ = pimpl_->converters_;
855 pimpl_->system_movers_ = pimpl_->movers_;
856 system_lcolor = lcolor;
858 // This one is edited through the preferences dialog.
859 if (!readRcFile("preferences"))
862 if (!readEncodingsFile("encodings", "unicodesymbols"))
864 if (!readLanguagesFile("languages"))
868 LYXERR(Debug::INIT, "Reading layouts...");
874 // read keymap and ui files in batch mode as well
875 // because InsetInfo needs to know these to produce
876 // the correct output
878 // Set the language defined by the user.
879 //setGuiLanguage(lyxrc.gui_language);
881 // Set up command definitions
882 pimpl_->toplevel_cmddef_.reset(new CmdDef);
883 pimpl_->toplevel_cmddef_->read(lyxrc.def_file);
886 pimpl_->toplevel_keymap_.reset(new KeyMap);
887 pimpl_->toplevel_keymap_->read("site");
888 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
889 // load user bind file user.bind
890 pimpl_->toplevel_keymap_->read("user");
892 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
895 if (!readUIFile(lyxrc.ui_file))
898 if (lyxerr.debugging(Debug::LYXRC))
901 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
902 if (!lyxrc.path_prefix.empty())
903 prependEnvPath("PATH", lyxrc.path_prefix);
905 FileName const document_path(lyxrc.document_path);
906 if (document_path.exists() && document_path.isDirectory())
907 package().document_dir() = document_path;
909 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
910 if (package().temp_dir().empty()) {
911 Alert::error(_("Could not create temporary directory"),
912 bformat(_("Could not create a temporary directory in\n"
913 "%1$s. Make sure that this\n"
914 "path exists and is writable and try again."),
915 from_utf8(lyxrc.tempdir_path)));
916 // createLyXTmpDir() tries sufficiently hard to create a
917 // usable temp dir, so the probability to come here is
918 // close to zero. We therefore don't try to overcome this
919 // problem with e.g. asking the user for a new path and
920 // trying again but simply exit.
924 LYXERR(Debug::INIT, "LyX tmp dir: `"
925 << package().temp_dir().absFilename() << '\'');
927 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
928 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
930 // This must happen after package initialization and after lyxrc is
931 // read, therefore it can't be done by a static object.
932 ConverterCache::init();
938 void LyX::emergencyCleanup() const
940 // what to do about tmpfiles is non-obvious. we would
941 // like to delete any we find, but our lyxdir might
942 // contain documents etc. which might be helpful on
945 pimpl_->buffer_list_.emergencyWriteAll();
947 if (pimpl_->lyx_server_)
948 pimpl_->lyx_server_->emergencyCleanup();
949 pimpl_->lyx_server_.reset();
950 pimpl_->lyx_socket_.reset();
955 void LyX::deadKeyBindings(KeyMap * kbmap)
957 // bindKeyings for transparent handling of deadkeys
958 // The keysyms are gotten from XFree86 X11R6
959 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
960 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
961 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
962 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
963 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
964 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
965 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
966 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
967 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
968 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
969 // nothing with this name
970 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
971 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
972 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
973 // nothing with this name either...
974 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
975 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
976 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
977 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
981 // return true if file does not exist or is older than configure.py.
982 static bool needsUpdate(string const & file)
984 // We cannot initialize configure_script directly because the package
985 // is not initialized yet when static objects are constructed.
986 static FileName configure_script;
987 static bool firstrun = true;
990 FileName(addName(package().system_support().absFilename(),
996 FileName(addName(package().user_support().absFilename(), file));
997 return !absfile.exists()
998 || configure_script.lastModified() > absfile.lastModified();
1002 bool LyX::queryUserLyXDir(bool explicit_userdir)
1004 // Does user directory exist?
1005 FileName const sup = package().user_support();
1006 if (sup.exists() && sup.isDirectory()) {
1007 first_start = false;
1009 return needsUpdate("lyxrc.defaults")
1010 || needsUpdate("lyxmodules.lst")
1011 || needsUpdate("textclass.lst")
1012 || needsUpdate("packages.lst");
1015 first_start = !explicit_userdir;
1017 // If the user specified explicitly a directory, ask whether
1018 // to create it. If the user says "no", then exit.
1019 if (explicit_userdir &&
1021 _("Missing user LyX directory"),
1022 bformat(_("You have specified a non-existent user "
1023 "LyX directory, %1$s.\n"
1024 "It is needed to keep your own configuration."),
1025 from_utf8(package().user_support().absFilename())),
1027 _("&Create directory"),
1029 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1030 earlyExit(EXIT_FAILURE);
1033 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1034 from_utf8(sup.absFilename()))) << endl;
1036 if (!sup.createDirectory(0755)) {
1037 // Failed, so let's exit.
1038 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1040 earlyExit(EXIT_FAILURE);
1047 bool LyX::readRcFile(string const & name)
1049 LYXERR(Debug::INIT, "About to read " << name << "... ");
1051 FileName const lyxrc_path = libFileSearch(string(), name);
1052 if (!lyxrc_path.empty()) {
1053 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
1054 if (lyxrc.read(lyxrc_path) < 0) {
1055 showFileError(name);
1059 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
1065 // Read the ui file `name'
1066 bool LyX::readUIFile(string const & name, bool include)
1076 struct keyword_item uitags[ui_last - 1] = {
1077 { "include", ui_include },
1078 { "menuset", ui_menuset },
1079 { "toolbars", ui_toolbars },
1080 { "toolbarset", ui_toolbarset }
1083 // Ensure that a file is read only once (prevents include loops)
1084 static std::list<string> uifiles;
1085 std::list<string>::const_iterator it = uifiles.begin();
1086 std::list<string>::const_iterator end = uifiles.end();
1087 it = std::find(it, end, name);
1089 LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1090 << "Is this an include loop?");
1094 LYXERR(Debug::INIT, "About to read " << name << "...");
1099 ui_path = libFileSearch("ui", name, "inc");
1100 if (ui_path.empty())
1101 ui_path = libFileSearch("ui",
1102 changeExtension(name, "inc"));
1105 ui_path = libFileSearch("ui", name, "ui");
1107 if (ui_path.empty()) {
1108 LYXERR(Debug::INIT, "Could not find " << name);
1109 showFileError(name);
1113 uifiles.push_back(name);
1115 LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1116 Lexer lex(uitags, ui_last - 1);
1117 lex.setFile(ui_path);
1119 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1123 if (lyxerr.debugging(Debug::PARSER))
1124 lex.printTable(lyxerr);
1126 while (lex.isOK()) {
1127 switch (lex.lex()) {
1130 string const file = lex.getString();
1131 if (!readUIFile(file, true))
1136 menubackend.read(lex);
1140 toolbarbackend.readToolbars(lex);
1144 toolbarbackend.readToolbarSettings(lex);
1148 if (!rtrim(lex.getString()).empty())
1149 lex.printError("LyX::ReadUIFile: "
1150 "Unknown menu tag: `$$Token'");
1158 // Read the languages file `name'
1159 bool LyX::readLanguagesFile(string const & name)
1161 LYXERR(Debug::INIT, "About to read " << name << "...");
1163 FileName const lang_path = libFileSearch(string(), name);
1164 if (lang_path.empty()) {
1165 showFileError(name);
1168 languages.read(lang_path);
1173 // Read the encodings file `name'
1174 bool LyX::readEncodingsFile(string const & enc_name,
1175 string const & symbols_name)
1177 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1178 << symbols_name << "...");
1180 FileName const symbols_path = libFileSearch(string(), symbols_name);
1181 if (symbols_path.empty()) {
1182 showFileError(symbols_name);
1186 FileName const enc_path = libFileSearch(string(), enc_name);
1187 if (enc_path.empty()) {
1188 showFileError(enc_name);
1191 encodings.read(enc_path, symbols_path);
1200 /// return the the number of arguments consumed
1201 typedef boost::function<int(string const &, string const &)> cmd_helper;
1203 int parse_dbg(string const & arg, string const &)
1206 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1207 Debug::showTags(lyxerr);
1210 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1212 lyxerr.level(Debug::value(arg));
1213 Debug::showLevel(lyxerr, lyxerr.level());
1218 int parse_help(string const &, string const &)
1221 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1222 "Command line switches (case sensitive):\n"
1223 "\t-help summarize LyX usage\n"
1224 "\t-userdir dir set user directory to dir\n"
1225 "\t-sysdir dir set system directory to dir\n"
1226 "\t-geometry WxH+X+Y set geometry of the main window\n"
1227 "\t-dbg feature[,feature]...\n"
1228 " select the features to debug.\n"
1229 " Type `lyx -dbg' to see the list of features\n"
1230 "\t-x [--execute] command\n"
1231 " where command is a lyx command.\n"
1232 "\t-e [--export] fmt\n"
1233 " where fmt is the export format of choice.\n"
1234 " Look on Tools->Preferences->File formats->Format\n"
1235 " to get an idea which parameters should be passed.\n"
1236 "\t-i [--import] fmt file.xxx\n"
1237 " where fmt is the import format of choice\n"
1238 " and file.xxx is the file to be imported.\n"
1239 "\t-version summarize version and build info\n"
1240 "Check the LyX man page for more details.")) << endl;
1246 int parse_version(string const &, string const &)
1248 lyxerr << "LyX " << lyx_version
1249 << " (" << lyx_release_date << ")" << endl;
1250 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1252 lyxerr << lyx_version_info << endl;
1258 int parse_sysdir(string const & arg, string const &)
1261 Alert::error(_("No system directory"),
1262 _("Missing directory for -sysdir switch"));
1265 cl_system_support = arg;
1270 int parse_userdir(string const & arg, string const &)
1273 Alert::error(_("No user directory"),
1274 _("Missing directory for -userdir switch"));
1277 cl_user_support = arg;
1282 int parse_execute(string const & arg, string const &)
1285 Alert::error(_("Incomplete command"),
1286 _("Missing command string after --execute switch"));
1294 int parse_export(string const & type, string const &)
1297 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1298 "--export switch")) << endl;
1301 batch = "buffer-export " + type;
1307 int parse_import(string const & type, string const & file)
1310 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1311 "--import switch")) << endl;
1315 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1319 batch = "buffer-import " + type + ' ' + file;
1324 int parse_geometry(string const & arg1, string const &)
1327 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1328 // remove also the arg
1331 // don't remove "-geometry"
1340 void LyX::easyParse(int & argc, char * argv[])
1342 std::map<string, cmd_helper> cmdmap;
1344 cmdmap["-dbg"] = parse_dbg;
1345 cmdmap["-help"] = parse_help;
1346 cmdmap["--help"] = parse_help;
1347 cmdmap["-version"] = parse_version;
1348 cmdmap["--version"] = parse_version;
1349 cmdmap["-sysdir"] = parse_sysdir;
1350 cmdmap["-userdir"] = parse_userdir;
1351 cmdmap["-x"] = parse_execute;
1352 cmdmap["--execute"] = parse_execute;
1353 cmdmap["-e"] = parse_export;
1354 cmdmap["--export"] = parse_export;
1355 cmdmap["-i"] = parse_import;
1356 cmdmap["--import"] = parse_import;
1357 cmdmap["-geometry"] = parse_geometry;
1359 for (int i = 1; i < argc; ++i) {
1360 std::map<string, cmd_helper>::const_iterator it
1361 = cmdmap.find(argv[i]);
1363 // don't complain if not found - may be parsed later
1364 if (it == cmdmap.end())
1368 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1370 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1372 int const remove = 1 + it->second(arg, arg2);
1374 // Now, remove used arguments by shifting
1375 // the following ones remove places down.
1378 for (int j = i; j < argc; ++j)
1379 argv[j] = argv[j + remove];
1384 pimpl_->batch_command = batch;
1388 FuncStatus getStatus(FuncRequest const & action)
1390 return LyX::ref().lyxFunc().getStatus(action);
1394 void dispatch(FuncRequest const & action)
1396 LyX::ref().lyxFunc().dispatch(action);
1400 BufferList & theBufferList()
1402 return LyX::ref().bufferList();
1406 LyXFunc & theLyXFunc()
1408 return LyX::ref().lyxFunc();
1412 Server & theServer()
1414 // FIXME: this should not be use_gui dependent
1415 BOOST_ASSERT(use_gui);
1416 return LyX::ref().server();
1420 ServerSocket & theServerSocket()
1422 // FIXME: this should not be use_gui dependent
1423 BOOST_ASSERT(use_gui);
1424 return LyX::ref().socket();
1428 KeyMap & theTopLevelKeymap()
1430 return LyX::ref().topLevelKeymap();
1434 Converters & theConverters()
1436 return LyX::ref().converters();
1440 Converters & theSystemConverters()
1442 return LyX::ref().systemConverters();
1446 Movers & theMovers()
1448 return LyX::ref().pimpl_->movers_;
1452 Mover const & getMover(std::string const & fmt)
1454 return LyX::ref().pimpl_->movers_(fmt);
1458 void setMover(std::string const & fmt, std::string const & command)
1460 LyX::ref().pimpl_->movers_.set(fmt, command);
1464 Movers & theSystemMovers()
1466 return LyX::ref().pimpl_->system_movers_;
1470 Messages & getMessages(std::string const & language)
1472 return LyX::ref().getMessages(language);
1476 Messages & getGuiMessages()
1478 return LyX::ref().getGuiMessages();