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/Dialogs.h"
52 #include "frontends/Gui.h"
53 #include "frontends/LyXView.h"
55 #include "support/environment.h"
56 #include "support/filetools.h"
57 #include "support/lstrings.h"
58 #include "support/lyxlib.h"
59 #include "support/ExceptionMessage.h"
60 #include "support/os.h"
61 #include "support/Package.h"
62 #include "support/Path.h"
63 #include "support/Systemcall.h"
65 #include <boost/bind.hpp>
66 #include <boost/scoped_ptr.hpp>
82 #ifndef CXX_GLOBAL_CSTD
90 using support::addName;
91 using support::addPath;
92 using support::bformat;
93 using support::changeExtension;
94 using support::createLyXTmpDir;
95 using support::FileName;
96 using support::fileSearch;
97 using support::getEnv;
98 using support::i18nLibFileSearch;
99 using support::libFileSearch;
100 using support::package;
101 using support::prependEnvPath;
102 using support::rtrim;
103 using support::Systemcall;
104 using frontend::LyXView;
106 namespace Alert = frontend::Alert;
107 namespace os = support::os;
111 // Are we using the GUI at all? We default to true and this is changed
112 // to false when the export feature is used.
116 bool quitting; // flag, that we are quitting the program
120 // Filled with the command line arguments "foo" of "-sysdir foo" or
122 string cl_system_support;
123 string cl_user_support;
125 std::string geometryArg;
127 LyX * singleton_ = 0;
129 void showFileError(string const & error)
131 Alert::warning(_("Could not read configuration file"),
132 bformat(_("Error while reading the configuration file\n%1$s.\n"
133 "Please check your installation."), from_utf8(error)));
137 void reconfigureUserLyXDir()
139 string const configure_command = package().configure_command();
141 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
142 support::PathChanger p(package().user_support());
144 one.startscript(Systemcall::Wait, configure_command);
145 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
151 /// The main application class private implementation.
156 // Set the default User Interface language as soon as possible.
157 // The language used will be derived from the environment
159 messages_["GUI"] = Messages();
161 /// our function handler
164 BufferList buffer_list_;
166 boost::scoped_ptr<KeyMap> toplevel_keymap_;
168 boost::scoped_ptr<CmdDef> toplevel_cmddef_;
170 boost::scoped_ptr<Server> lyx_server_;
172 boost::scoped_ptr<ServerSocket> lyx_socket_;
174 boost::scoped_ptr<frontend::Application> application_;
175 /// lyx session, containing lastfiles, lastfilepos, and lastopened
176 boost::scoped_ptr<Session> session_;
178 /// Files to load at start.
179 vector<FileName> files_to_load_;
181 /// The messages translators.
182 map<string, Messages> messages_;
184 /// The file converters.
185 Converters converters_;
187 // The system converters copy after reading lyxrc.defaults.
188 Converters system_converters_;
193 Movers system_movers_;
195 /// has this user started lyx for the first time?
197 /// the parsed command line batch command if any
198 std::string batch_command;
202 frontend::Application * theApp()
205 return singleton_->pimpl_->application_.get();
219 BOOST_ASSERT(singleton_);
224 LyX const & LyX::cref()
226 BOOST_ASSERT(singleton_);
239 BufferList & LyX::bufferList()
241 return pimpl_->buffer_list_;
245 BufferList const & LyX::bufferList() const
247 return pimpl_->buffer_list_;
251 Session & LyX::session()
253 BOOST_ASSERT(pimpl_->session_.get());
254 return *pimpl_->session_.get();
258 Session const & LyX::session() const
260 BOOST_ASSERT(pimpl_->session_.get());
261 return *pimpl_->session_.get();
265 LyXFunc & LyX::lyxFunc()
267 return pimpl_->lyxfunc_;
271 LyXFunc const & LyX::lyxFunc() const
273 return pimpl_->lyxfunc_;
277 Server & LyX::server()
279 BOOST_ASSERT(pimpl_->lyx_server_.get());
280 return *pimpl_->lyx_server_.get();
284 Server const & LyX::server() const
286 BOOST_ASSERT(pimpl_->lyx_server_.get());
287 return *pimpl_->lyx_server_.get();
291 ServerSocket & LyX::socket()
293 BOOST_ASSERT(pimpl_->lyx_socket_.get());
294 return *pimpl_->lyx_socket_.get();
298 ServerSocket const & LyX::socket() const
300 BOOST_ASSERT(pimpl_->lyx_socket_.get());
301 return *pimpl_->lyx_socket_.get();
305 frontend::Application & LyX::application()
307 BOOST_ASSERT(pimpl_->application_.get());
308 return *pimpl_->application_.get();
312 frontend::Application const & LyX::application() const
314 BOOST_ASSERT(pimpl_->application_.get());
315 return *pimpl_->application_.get();
319 KeyMap & LyX::topLevelKeymap()
321 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
322 return *pimpl_->toplevel_keymap_.get();
326 CmdDef & LyX::topLevelCmdDef()
328 BOOST_ASSERT(pimpl_->toplevel_cmddef_.get());
329 return *pimpl_->toplevel_cmddef_.get();
333 Converters & LyX::converters()
335 return pimpl_->converters_;
339 Converters & LyX::systemConverters()
341 return pimpl_->system_converters_;
345 KeyMap const & LyX::topLevelKeymap() const
347 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
348 return *pimpl_->toplevel_keymap_.get();
352 Messages & LyX::getMessages(std::string const & language)
354 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
356 if (it != pimpl_->messages_.end())
359 std::pair<map<string, Messages>::iterator, bool> result =
360 pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
362 BOOST_ASSERT(result.second);
363 return result.first->second;
367 Messages & LyX::getGuiMessages()
369 return pimpl_->messages_["GUI"];
373 void LyX::setGuiLanguage(std::string const & language)
375 pimpl_->messages_["GUI"] = Messages(language);
379 Buffer const * LyX::updateInset(Inset const * inset) const
381 if (quitting || !inset)
384 Buffer const * buffer_ptr = 0;
385 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
386 vector<int>::const_iterator it = view_ids.begin();
387 vector<int>::const_iterator const end = view_ids.end();
388 for (; it != end; ++it) {
390 pimpl_->application_->gui().view(*it).updateInset(inset);
398 void LyX::hideDialogs(std::string const & name, Inset * inset) const
400 if (quitting || !use_gui)
403 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
404 vector<int>::const_iterator it = view_ids.begin();
405 vector<int>::const_iterator const end = view_ids.end();
406 for (; it != end; ++it)
407 pimpl_->application_->gui().view(*it).getDialogs().
412 int LyX::exec(int & argc, char * argv[])
414 // Here we need to parse the command line. At least
415 // we need to parse for "-dbg" and "-help"
416 easyParse(argc, argv);
419 support::init_package(to_utf8(from_local8bit(argv[0])),
420 cl_system_support, cl_user_support,
421 support::top_build_dir_is_one_level_up);
422 } catch (support::ExceptionMessage const & message) {
423 if (message.type_ == support::ErrorException) {
424 Alert::error(message.title_, message.details_);
426 } else if (message.type_ == support::WarningException) {
427 Alert::warning(message.title_, message.details_);
431 // Reinit the messages machinery in case package() knows
432 // something interesting about the locale directory.
436 // FIXME: create a ConsoleApplication
437 int exit_status = init(argc, argv);
445 if (pimpl_->batch_command.empty() || pimpl_->buffer_list_.empty()) {
450 BufferList::iterator begin = pimpl_->buffer_list_.begin();
452 bool final_success = false;
453 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
455 if (buf != buf->masterBuffer())
457 bool success = false;
458 buf->dispatch(pimpl_->batch_command, &success);
459 final_success |= success;
462 return !final_success;
465 // Let the frontend parse and remove all arguments that it knows
466 pimpl_->application_.reset(createApplication(argc, argv));
470 // Parse and remove all known arguments in the LyX singleton
471 // Give an error for all remaining ones.
472 int exit_status = init(argc, argv);
474 // Kill the application object before exiting.
475 pimpl_->application_.reset();
482 /* Create a CoreApplication class that will provide the main event loop
483 * and the socket callback registering. With Qt4, only QtCore
484 * library would be needed.
485 * When this is done, a server_mode could be created and the following two
486 * line would be moved out from here.
488 // Note: socket callback must be registered after init(argc, argv)
489 // such that package().temp_dir() is properly initialized.
490 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
491 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
492 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
494 // Start the real execution loop.
495 exit_status = pimpl_->application_->exec();
503 void LyX::prepareExit()
505 // Clear the clipboard and selection stack:
506 cap::clearCutStack();
507 cap::clearSelection();
509 // Set a flag that we do quitting from the program,
510 // so no refreshes are necessary.
513 // close buffers first
514 pimpl_->buffer_list_.closeAll();
516 // do any other cleanup procedures now
517 if (package().temp_dir() != package().system_temp_dir()) {
518 LYXERR(Debug::INFO) << "Deleting tmp dir "
519 << package().temp_dir().absFilename() << endl;
521 if (!package().temp_dir().destroyDirectory()) {
522 docstring const msg =
523 bformat(_("Unable to remove the temporary directory %1$s"),
524 from_utf8(package().temp_dir().absFilename()));
525 Alert::warning(_("Unable to remove temporary directory"), msg);
530 if (pimpl_->session_)
531 pimpl_->session_->writeFile();
532 pimpl_->session_.reset();
533 pimpl_->lyx_server_.reset();
534 pimpl_->lyx_socket_.reset();
537 // Kill the application object before exiting. This avoids crashes
538 // when exiting on Linux.
539 if (pimpl_->application_)
540 pimpl_->application_.reset();
544 void LyX::earlyExit(int status)
546 BOOST_ASSERT(pimpl_->application_.get());
547 // LyX::pimpl_::application_ is not initialised at this
548 // point so it's safe to just exit after some cleanup.
554 int LyX::init(int & argc, char * argv[])
556 // check for any spurious extra arguments
557 // other than documents
558 for (int argi = 1; argi < argc ; ++argi) {
559 if (argv[argi][0] == '-') {
561 bformat(_("Wrong command line option `%1$s'. Exiting."),
562 from_utf8(argv[argi]))) << endl;
567 // Initialization of LyX (reads lyxrc and more)
568 LYXERR(Debug::INIT) << "Initializing LyX::init..." << endl;
569 bool success = init();
570 LYXERR(Debug::INIT) << "Initializing LyX::init...done" << endl;
574 for (int argi = argc - 1; argi >= 1; --argi) {
575 // get absolute path of file and add ".lyx" to
576 // the filename if necessary
577 pimpl_->files_to_load_.push_back(fileSearch(string(),
578 os::internal_path(to_utf8(from_local8bit(argv[argi]))),
579 "lyx", support::allow_unreadable));
583 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
589 void LyX::addFileToLoad(FileName const & fname)
591 vector<FileName>::const_iterator cit = std::find(
592 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
595 if (cit == pimpl_->files_to_load_.end())
596 pimpl_->files_to_load_.push_back(fname);
600 void LyX::loadFiles()
602 vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
603 vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
605 for (; it != end; ++it) {
609 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
610 if (buf->loadLyXFile(*it)) {
611 ErrorList const & el = buf->errorList("Parse");
613 for_each(el.begin(), el.end(),
614 boost::bind(&LyX::printError, this, _1));
617 pimpl_->buffer_list_.release(buf);
622 void LyX::execBatchCommands()
624 // The advantage of doing this here is that the event loop
625 // is already started. So any need for interaction will be
629 // if reconfiguration is needed.
630 if (textclasslist.empty()) {
631 switch (Alert::prompt(
632 _("No textclass is found"),
633 _("LyX cannot continue because no textclass is found. "
634 "You can either reconfigure normally, or reconfigure using "
635 "default textclasses, or quit LyX."),
642 // regular reconfigure
643 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
646 // reconfigure --without-latex-config
647 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
648 " --without-latex-config"));
651 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
655 // Execute batch commands if available
656 if (pimpl_->batch_command.empty())
659 LYXERR(Debug::INIT) << "About to handle -x '"
660 << pimpl_->batch_command << '\'' << endl;
662 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
666 void LyX::restoreGuiSession()
668 LyXView * view = newLyXView();
670 // if there is no valid class list, do not load any file.
671 if (textclasslist.empty())
674 // if some files were specified at command-line we assume that the
675 // user wants to edit *these* files and not to restore the session.
676 if (!pimpl_->files_to_load_.empty()) {
677 for_each(pimpl_->files_to_load_.begin(),
678 pimpl_->files_to_load_.end(),
679 bind(&LyXView::loadLyXFile, view, _1, true));
680 // clear this list to save a few bytes of RAM
681 pimpl_->files_to_load_.clear();
682 pimpl_->session_->lastOpened().clear();
684 } else if (lyxrc.load_session) {
685 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
686 // do not add to the lastfile list since these files are restored from
687 // last session, and should be already there (regular files), or should
688 // not be added at all (help files).
689 for_each(lastopened.begin(), lastopened.end(),
690 bind(&LyXView::loadLyXFile, view, _1, false));
692 // clear this list to save a few bytes of RAM
693 pimpl_->session_->lastOpened().clear();
696 BufferList::iterator I = pimpl_->buffer_list_.begin();
697 BufferList::iterator end = pimpl_->buffer_list_.end();
698 for (; I != end; ++I) {
700 if (buf != buf->masterBuffer())
705 // FIXME: Switch to the last loaded Buffer. This must not be the first one
706 // because the Buffer won't be connected in this case. The correct solution
707 // would be to avoid the manual connection of the current Buffer in LyXView.
708 if (!pimpl_->buffer_list_.empty())
709 view->setBuffer(pimpl_->buffer_list_.last());
713 LyXView * LyX::newLyXView()
718 // create the main window
719 LyXView * view = &pimpl_->application_->createView(geometryArg);
727 The SIGHUP signal does not exist on Windows and does not need to be handled.
729 Windows handles SIGFPE and SIGSEGV signals as expected.
731 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
732 cause a new thread to be spawned. This may well result in unexpected
733 behaviour by the single-threaded LyX.
735 SIGTERM signals will come only from another process actually sending
736 that signal using 'raise' in Windows' POSIX compatability layer. It will
737 not come from the general "terminate process" methods that everyone
738 actually uses (and which can't be trapped). Killing an app 'politely' on
739 Windows involves first sending a WM_CLOSE message, something that is
740 caught already by the Qt frontend.
742 For more information see:
744 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
745 ...signals are mostly useless on Windows for a variety of reasons that are
748 'UNIX Application Migration Guide, Chapter 9'
749 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
751 'How To Terminate an Application "Cleanly" in Win32'
752 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
756 static void error_handler(int err_sig)
758 // Throw away any signals other than the first one received.
759 static sig_atomic_t handling_error = false;
762 handling_error = true;
764 // We have received a signal indicating a fatal error, so
765 // try and save the data ASAP.
766 LyX::cref().emergencyCleanup();
768 // These lyxerr calls may or may not work:
770 // Signals are asynchronous, so the main program may be in a very
771 // fragile state when a signal is processed and thus while a signal
772 // handler function executes.
773 // In general, therefore, we should avoid performing any
774 // I/O operations or calling most library and system functions from
777 // This shouldn't matter here, however, as we've already invoked
782 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
786 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
789 lyxerr << "\nlyx: SIGSEGV signal caught\n"
790 "Sorry, you have found a bug in LyX. "
791 "Please read the bug-reporting instructions "
792 "in Help->Introduction and send us a bug report, "
793 "if necessary. Thanks !\nBye." << endl;
801 // Deinstall the signal handlers
803 signal(SIGHUP, SIG_DFL);
805 signal(SIGINT, SIG_DFL);
806 signal(SIGFPE, SIG_DFL);
807 signal(SIGSEGV, SIG_DFL);
808 signal(SIGTERM, SIG_DFL);
811 if (err_sig == SIGSEGV ||
812 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
814 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
823 void LyX::printError(ErrorItem const & ei)
825 docstring tmp = _("LyX: ") + ei.error + char_type(':')
827 std::cerr << to_utf8(tmp) << std::endl;
831 void LyX::initGuiFont()
833 if (lyxrc.roman_font_name.empty())
834 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
836 if (lyxrc.sans_font_name.empty())
837 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
839 if (lyxrc.typewriter_font_name.empty())
840 lyxrc.typewriter_font_name
841 = pimpl_->application_->typewriterFontName();
848 signal(SIGHUP, error_handler);
850 signal(SIGFPE, error_handler);
851 signal(SIGSEGV, error_handler);
852 signal(SIGINT, error_handler);
853 signal(SIGTERM, error_handler);
854 // SIGPIPE can be safely ignored.
856 lyxrc.tempdir_path = package().temp_dir().absFilename();
857 lyxrc.document_path = package().document_dir().absFilename();
859 if (lyxrc.template_path.empty()) {
860 lyxrc.template_path = addPath(package().system_support().absFilename(),
865 // Read configuration files
868 // This one may have been distributed along with LyX.
869 if (!readRcFile("lyxrc.dist"))
872 // Set the language defined by the distributor.
873 //setGuiLanguage(lyxrc.gui_language);
875 // Set the PATH correctly.
876 #if !defined (USE_POSIX_PACKAGING)
877 // Add the directory containing the LyX executable to the path
878 // so that LyX can find things like tex2lyx.
879 if (package().build_support().empty())
880 prependEnvPath("PATH", package().binary_dir().absFilename());
882 if (!lyxrc.path_prefix.empty())
883 prependEnvPath("PATH", lyxrc.path_prefix);
885 // Check that user LyX directory is ok.
886 if (queryUserLyXDir(package().explicit_user_support()))
887 reconfigureUserLyXDir();
889 // no need for a splash when there is no GUI
894 // This one is generated in user_support directory by lib/configure.py.
895 if (!readRcFile("lyxrc.defaults"))
898 // Query the OS to know what formats are viewed natively
899 formats.setAutoOpen();
901 // Read lyxrc.dist again to be able to override viewer auto-detection.
902 readRcFile("lyxrc.dist");
904 system_lyxrc = lyxrc;
905 system_formats = formats;
906 pimpl_->system_converters_ = pimpl_->converters_;
907 pimpl_->system_movers_ = pimpl_->movers_;
908 system_lcolor = lcolor;
910 // This one is edited through the preferences dialog.
911 if (!readRcFile("preferences"))
914 if (!readEncodingsFile("encodings", "unicodesymbols"))
916 if (!readLanguagesFile("languages"))
920 LYXERR(Debug::INIT) << "Reading layouts..." << endl;
926 // read keymap and ui files in batch mode as well
927 // because InsetInfo needs to know these to produce
928 // the correct output
930 // Set the language defined by the user.
931 //setGuiLanguage(lyxrc.gui_language);
933 // Set up command definitions
934 pimpl_->toplevel_cmddef_.reset(new CmdDef);
935 pimpl_->toplevel_cmddef_->read(lyxrc.def_file);
938 pimpl_->toplevel_keymap_.reset(new KeyMap);
939 pimpl_->toplevel_keymap_->read("site");
940 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
941 // load user bind file user.bind
942 pimpl_->toplevel_keymap_->read("user");
944 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
947 if (!readUIFile(lyxrc.ui_file))
950 if (lyxerr.debugging(Debug::LYXRC))
953 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
954 if (!lyxrc.path_prefix.empty())
955 prependEnvPath("PATH", lyxrc.path_prefix);
957 FileName const document_path(lyxrc.document_path);
958 if (document_path.exists() && document_path.isDirectory())
959 package().document_dir() = document_path;
961 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
962 if (package().temp_dir().empty()) {
963 Alert::error(_("Could not create temporary directory"),
964 bformat(_("Could not create a temporary directory in\n"
965 "%1$s. Make sure that this\n"
966 "path exists and is writable and try again."),
967 from_utf8(lyxrc.tempdir_path)));
968 // createLyXTmpDir() tries sufficiently hard to create a
969 // usable temp dir, so the probability to come here is
970 // close to zero. We therefore don't try to overcome this
971 // problem with e.g. asking the user for a new path and
972 // trying again but simply exit.
976 LYXERR(Debug::INIT) << "LyX tmp dir: `"
977 << package().temp_dir().absFilename()
980 LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
981 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
983 // This must happen after package initialization and after lyxrc is
984 // read, therefore it can't be done by a static object.
985 ConverterCache::init();
991 void LyX::emergencyCleanup() const
993 // what to do about tmpfiles is non-obvious. we would
994 // like to delete any we find, but our lyxdir might
995 // contain documents etc. which might be helpful on
998 pimpl_->buffer_list_.emergencyWriteAll();
1000 if (pimpl_->lyx_server_)
1001 pimpl_->lyx_server_->emergencyCleanup();
1002 pimpl_->lyx_server_.reset();
1003 pimpl_->lyx_socket_.reset();
1008 void LyX::deadKeyBindings(KeyMap * kbmap)
1010 // bindKeyings for transparent handling of deadkeys
1011 // The keysyms are gotten from XFree86 X11R6
1012 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1013 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1014 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1015 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1016 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1017 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1018 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1019 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1020 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1021 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1022 // nothing with this name
1023 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1024 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1025 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1026 // nothing with this name either...
1027 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1028 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1029 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1030 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1034 // return true if file does not exist or is older than configure.py.
1035 static bool needsUpdate(string const & file)
1037 // We cannot initialize configure_script directly because the package
1038 // is not initialized yet when static objects are constructed.
1039 static FileName configure_script;
1040 static bool firstrun = true;
1043 FileName(addName(package().system_support().absFilename(),
1049 FileName(addName(package().user_support().absFilename(), file));
1050 return !absfile.exists()
1051 || configure_script.lastModified() > absfile.lastModified();
1055 bool LyX::queryUserLyXDir(bool explicit_userdir)
1057 // Does user directory exist?
1058 FileName const sup = package().user_support();
1059 if (sup.exists() && sup.isDirectory()) {
1060 first_start = false;
1062 return needsUpdate("lyxrc.defaults")
1063 || needsUpdate("lyxmodules.lst")
1064 || needsUpdate("textclass.lst")
1065 || needsUpdate("packages.lst");
1068 first_start = !explicit_userdir;
1070 // If the user specified explicitly a directory, ask whether
1071 // to create it. If the user says "no", then exit.
1072 if (explicit_userdir &&
1074 _("Missing user LyX directory"),
1075 bformat(_("You have specified a non-existent user "
1076 "LyX directory, %1$s.\n"
1077 "It is needed to keep your own configuration."),
1078 from_utf8(package().user_support().absFilename())),
1080 _("&Create directory"),
1082 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1083 earlyExit(EXIT_FAILURE);
1086 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1087 from_utf8(sup.absFilename()))) << endl;
1089 if (!sup.createDirectory(0755)) {
1090 // Failed, so let's exit.
1091 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1093 earlyExit(EXIT_FAILURE);
1100 bool LyX::readRcFile(string const & name)
1102 LYXERR(Debug::INIT) << "About to read " << name << "... ";
1104 FileName const lyxrc_path = libFileSearch(string(), name);
1105 if (!lyxrc_path.empty()) {
1107 LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
1109 if (lyxrc.read(lyxrc_path) < 0) {
1110 showFileError(name);
1114 LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
1120 // Read the ui file `name'
1121 bool LyX::readUIFile(string const & name, bool include)
1131 struct keyword_item uitags[ui_last - 1] = {
1132 { "include", ui_include },
1133 { "menuset", ui_menuset },
1134 { "toolbars", ui_toolbars },
1135 { "toolbarset", ui_toolbarset }
1138 // Ensure that a file is read only once (prevents include loops)
1139 static std::list<string> uifiles;
1140 std::list<string>::const_iterator it = uifiles.begin();
1141 std::list<string>::const_iterator end = uifiles.end();
1142 it = std::find(it, end, name);
1144 LYXERR(Debug::INIT) << "UI file '" << name
1145 << "' has been read already. "
1146 << "Is this an include loop?"
1151 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1156 ui_path = libFileSearch("ui", name, "inc");
1157 if (ui_path.empty())
1158 ui_path = libFileSearch("ui",
1159 changeExtension(name, "inc"));
1162 ui_path = libFileSearch("ui", name, "ui");
1164 if (ui_path.empty()) {
1165 LYXERR(Debug::INIT) << "Could not find " << name << endl;
1166 showFileError(name);
1170 uifiles.push_back(name);
1172 LYXERR(Debug::INIT) << "Found " << name
1173 << " in " << ui_path << endl;
1174 Lexer lex(uitags, ui_last - 1);
1175 lex.setFile(ui_path);
1177 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1181 if (lyxerr.debugging(Debug::PARSER))
1182 lex.printTable(lyxerr);
1184 while (lex.isOK()) {
1185 switch (lex.lex()) {
1188 string const file = lex.getString();
1189 if (!readUIFile(file, true))
1194 menubackend.read(lex);
1198 toolbarbackend.readToolbars(lex);
1202 toolbarbackend.readToolbarSettings(lex);
1206 if (!rtrim(lex.getString()).empty())
1207 lex.printError("LyX::ReadUIFile: "
1208 "Unknown menu tag: `$$Token'");
1216 // Read the languages file `name'
1217 bool LyX::readLanguagesFile(string const & name)
1219 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1221 FileName const lang_path = libFileSearch(string(), name);
1222 if (lang_path.empty()) {
1223 showFileError(name);
1226 languages.read(lang_path);
1231 // Read the encodings file `name'
1232 bool LyX::readEncodingsFile(string const & enc_name,
1233 string const & symbols_name)
1235 LYXERR(Debug::INIT) << "About to read " << enc_name << " and "
1236 << symbols_name << "..." << endl;
1238 FileName const symbols_path = libFileSearch(string(), symbols_name);
1239 if (symbols_path.empty()) {
1240 showFileError(symbols_name);
1244 FileName const enc_path = libFileSearch(string(), enc_name);
1245 if (enc_path.empty()) {
1246 showFileError(enc_name);
1249 encodings.read(enc_path, symbols_path);
1258 /// return the the number of arguments consumed
1259 typedef boost::function<int(string const &, string const &)> cmd_helper;
1261 int parse_dbg(string const & arg, string const &)
1264 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1265 Debug::showTags(lyxerr);
1268 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1270 lyxerr.level(Debug::value(arg));
1271 Debug::showLevel(lyxerr, lyxerr.level());
1276 int parse_help(string const &, string const &)
1279 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1280 "Command line switches (case sensitive):\n"
1281 "\t-help summarize LyX usage\n"
1282 "\t-userdir dir set user directory to dir\n"
1283 "\t-sysdir dir set system directory to dir\n"
1284 "\t-geometry WxH+X+Y set geometry of the main window\n"
1285 "\t-dbg feature[,feature]...\n"
1286 " select the features to debug.\n"
1287 " Type `lyx -dbg' to see the list of features\n"
1288 "\t-x [--execute] command\n"
1289 " where command is a lyx command.\n"
1290 "\t-e [--export] fmt\n"
1291 " where fmt is the export format of choice.\n"
1292 " Look on Tools->Preferences->File formats->Format\n"
1293 " to get an idea which parameters should be passed.\n"
1294 "\t-i [--import] fmt file.xxx\n"
1295 " where fmt is the import format of choice\n"
1296 " and file.xxx is the file to be imported.\n"
1297 "\t-version summarize version and build info\n"
1298 "Check the LyX man page for more details.")) << endl;
1304 int parse_version(string const &, string const &)
1306 lyxerr << "LyX " << lyx_version
1307 << " (" << lyx_release_date << ")" << endl;
1308 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1310 lyxerr << lyx_version_info << endl;
1316 int parse_sysdir(string const & arg, string const &)
1319 Alert::error(_("No system directory"),
1320 _("Missing directory for -sysdir switch"));
1323 cl_system_support = arg;
1328 int parse_userdir(string const & arg, string const &)
1331 Alert::error(_("No user directory"),
1332 _("Missing directory for -userdir switch"));
1335 cl_user_support = arg;
1340 int parse_execute(string const & arg, string const &)
1343 Alert::error(_("Incomplete command"),
1344 _("Missing command string after --execute switch"));
1352 int parse_export(string const & type, string const &)
1355 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1356 "--export switch")) << endl;
1359 batch = "buffer-export " + type;
1365 int parse_import(string const & type, string const & file)
1368 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1369 "--import switch")) << endl;
1373 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1377 batch = "buffer-import " + type + ' ' + file;
1382 int parse_geometry(string const & arg1, string const &)
1385 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1386 // remove also the arg
1389 // don't remove "-geometry"
1398 void LyX::easyParse(int & argc, char * argv[])
1400 std::map<string, cmd_helper> cmdmap;
1402 cmdmap["-dbg"] = parse_dbg;
1403 cmdmap["-help"] = parse_help;
1404 cmdmap["--help"] = parse_help;
1405 cmdmap["-version"] = parse_version;
1406 cmdmap["--version"] = parse_version;
1407 cmdmap["-sysdir"] = parse_sysdir;
1408 cmdmap["-userdir"] = parse_userdir;
1409 cmdmap["-x"] = parse_execute;
1410 cmdmap["--execute"] = parse_execute;
1411 cmdmap["-e"] = parse_export;
1412 cmdmap["--export"] = parse_export;
1413 cmdmap["-i"] = parse_import;
1414 cmdmap["--import"] = parse_import;
1415 cmdmap["-geometry"] = parse_geometry;
1417 for (int i = 1; i < argc; ++i) {
1418 std::map<string, cmd_helper>::const_iterator it
1419 = cmdmap.find(argv[i]);
1421 // don't complain if not found - may be parsed later
1422 if (it == cmdmap.end())
1426 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1428 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1430 int const remove = 1 + it->second(arg, arg2);
1432 // Now, remove used arguments by shifting
1433 // the following ones remove places down.
1436 for (int j = i; j < argc; ++j)
1437 argv[j] = argv[j + remove];
1442 pimpl_->batch_command = batch;
1446 FuncStatus getStatus(FuncRequest const & action)
1448 return LyX::ref().lyxFunc().getStatus(action);
1452 void dispatch(FuncRequest const & action)
1454 LyX::ref().lyxFunc().dispatch(action);
1458 BufferList & theBufferList()
1460 return LyX::ref().bufferList();
1464 LyXFunc & theLyXFunc()
1466 return LyX::ref().lyxFunc();
1470 Server & theServer()
1472 // FIXME: this should not be use_gui dependent
1473 BOOST_ASSERT(use_gui);
1474 return LyX::ref().server();
1478 ServerSocket & theServerSocket()
1480 // FIXME: this should not be use_gui dependent
1481 BOOST_ASSERT(use_gui);
1482 return LyX::ref().socket();
1486 KeyMap & theTopLevelKeymap()
1488 return LyX::ref().topLevelKeymap();
1492 Converters & theConverters()
1494 return LyX::ref().converters();
1498 Converters & theSystemConverters()
1500 return LyX::ref().systemConverters();
1504 Movers & theMovers()
1506 return LyX::ref().pimpl_->movers_;
1510 Mover const & getMover(std::string const & fmt)
1512 return LyX::ref().pimpl_->movers_(fmt);
1516 void setMover(std::string const & fmt, std::string const & command)
1518 LyX::ref().pimpl_->movers_.set(fmt, command);
1522 Movers & theSystemMovers()
1524 return LyX::ref().pimpl_->system_movers_;
1528 Messages & getMessages(std::string const & language)
1530 return LyX::ref().getMessages(language);
1534 Messages & getGuiMessages()
1536 return LyX::ref().getGuiMessages();