3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
20 #include "ConverterCache.h"
22 #include "buffer_funcs.h"
23 #include "bufferlist.h"
24 #include "converter.h"
27 #include "errorlist.h"
35 #include "LyXAction.h"
39 #include "lyxserver.h"
40 #include "lyxsocket.h"
41 #include "lyxtextclasslist.h"
42 #include "MenuBackend.h"
45 #include "ToolbarBackend.h"
47 #include "frontends/Alert.h"
48 #include "frontends/Application.h"
49 #include "frontends/Gui.h"
50 #include "frontends/LyXView.h"
52 #include "support/environment.h"
53 #include "support/filetools.h"
54 #include "support/lyxlib.h"
55 #include "support/convert.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"
61 #include "support/unicode.h"
63 #include <boost/bind.hpp>
64 #include <boost/filesystem/operations.hpp>
75 using support::addName;
76 using support::addPath;
77 using support::bformat;
78 using support::changeExtension;
79 using support::createDirectory;
80 using support::createLyXTmpDir;
81 using support::destroyDir;
82 using support::FileName;
83 using support::fileSearch;
84 using support::getEnv;
85 using support::i18nLibFileSearch;
86 using support::libFileSearch;
87 using support::package;
88 using support::prependEnvPath;
90 using support::Systemcall;
92 namespace Alert = frontend::Alert;
93 namespace os = support::os;
94 namespace fs = boost::filesystem;
103 #ifndef CXX_GLOBAL_CSTD
110 /// are we using the GUI at all?
112 * We default to true and this is changed to false when the export feature is used.
119 // Filled with the command line arguments "foo" of "-sysdir foo" or
121 string cl_system_support;
122 string cl_user_support;
124 std::string geometryArg;
126 LyX * singleton_ = 0;
128 void showFileError(string const & error)
130 Alert::warning(_("Could not read configuration file"),
131 bformat(_("Error while reading the configuration file\n%1$s.\n"
132 "Please check your installation."), from_utf8(error)));
136 void reconfigureUserLyXDir()
138 string const configure_command = package().configure_command();
140 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
141 support::Path p(package().user_support());
143 one.startscript(Systemcall::Wait, configure_command);
144 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
150 /// The main application class private implementation.
151 struct LyX::Singletons
153 Singletons(): iconv(ucs4_codeset, "UTF-8")
155 // Set the default User Interface language as soon as possible.
156 // The language used will be derived from the environment
158 messages_["GUI"] = Messages();
160 /// our function handler
163 BufferList buffer_list_;
165 boost::scoped_ptr<kb_keymap> toplevel_keymap_;
167 boost::scoped_ptr<LyXServer> lyx_server_;
169 boost::scoped_ptr<LyXServerSocket> lyx_socket_;
171 boost::scoped_ptr<frontend::Application> application_;
172 /// lyx session, containing lastfiles, lastfilepos, and lastopened
173 boost::scoped_ptr<Session> session_;
176 IconvProcessor iconv;
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_;
194 Movers system_movers_;
198 frontend::Application * theApp()
201 return singleton_->pimpl_->application_.get();
214 BOOST_ASSERT(singleton_);
219 LyX const & LyX::cref()
221 BOOST_ASSERT(singleton_);
230 pimpl_.reset(new Singletons);
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 LyXServer & LyX::server()
275 BOOST_ASSERT(pimpl_->lyx_server_.get());
276 return *pimpl_->lyx_server_.get();
280 LyXServer const & LyX::server() const
282 BOOST_ASSERT(pimpl_->lyx_server_.get());
283 return *pimpl_->lyx_server_.get();
287 LyXServerSocket & LyX::socket()
289 BOOST_ASSERT(pimpl_->lyx_socket_.get());
290 return *pimpl_->lyx_socket_.get();
294 LyXServerSocket 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 kb_keymap & LyX::topLevelKeymap()
317 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
318 return *pimpl_->toplevel_keymap_.get();
322 Converters & LyX::converters()
324 return pimpl_->converters_;
328 Converters & LyX::systemConverters()
330 return pimpl_->system_converters_;
334 IconvProcessor & LyX::iconvProcessor()
336 return pimpl_->iconv;
340 kb_keymap const & LyX::topLevelKeymap() const
342 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
343 return *pimpl_->toplevel_keymap_.get();
347 Messages & LyX::getMessages(std::string const & language)
349 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
351 if (it != pimpl_->messages_.end())
354 std::pair<map<string, Messages>::iterator, bool> result =
355 pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
357 BOOST_ASSERT(result.second);
358 return result.first->second;
362 Messages & LyX::getGuiMessages()
364 return pimpl_->messages_["GUI"];
368 void LyX::setGuiLanguage(std::string const & language)
370 pimpl_->messages_["GUI"] = Messages(language);
374 Buffer const * const LyX::updateInset(InsetBase const * inset) const
379 Buffer const * buffer_ptr = 0;
380 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
381 vector<int>::const_iterator it = view_ids.begin();
382 vector<int>::const_iterator const end = view_ids.end();
383 for (; it != end; ++it) {
385 pimpl_->application_->gui().view(*it).updateInset(inset);
393 int LyX::exec(int & argc, char * argv[])
395 // Here we need to parse the command line. At least
396 // we need to parse for "-dbg" and "-help"
397 easyParse(argc, argv);
399 try { support::init_package(to_utf8(from_local8bit(argv[0])),
400 cl_system_support, cl_user_support,
401 support::top_build_dir_is_one_level_up);
402 } catch (support::ExceptionMessage const & message) {
403 if (message.type_ == support::ErrorException) {
404 Alert::error(message.title_, message.details_);
406 } else if (message.type_ == support::WarningException) {
407 Alert::warning(message.title_, message.details_);
412 // FIXME: create a ConsoleApplication
413 int exit_status = init(argc, argv);
421 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
426 BufferList::iterator begin = pimpl_->buffer_list_.begin();
427 BufferList::iterator end = pimpl_->buffer_list_.end();
429 bool final_success = false;
430 for (BufferList::iterator I = begin; I != end; ++I) {
432 bool success = false;
433 buf->dispatch(batch_command, &success);
434 final_success |= success;
437 return !final_success;
440 // Force adding of font path _before_ Application is initialized
441 support::os::addFontResources();
443 // Let the frontend parse and remove all arguments that it knows
444 pimpl_->application_.reset(createApplication(argc, argv));
448 // Parse and remove all known arguments in the LyX singleton
449 // Give an error for all remaining ones.
450 int exit_status = init(argc, argv);
452 // Kill the application object before exiting.
453 pimpl_->application_.reset();
460 /* Create a CoreApplication class that will provide the main event loop
461 * and the socket callback registering. With Qt4, only QtCore
462 * library would be needed.
463 * When this is done, a server_mode could be created and the following two
464 * line would be moved out from here.
466 // Note: socket callback must be registered after init(argc, argv)
467 // such that package().temp_dir() is properly initialized.
468 pimpl_->lyx_server_.reset(new LyXServer(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
469 pimpl_->lyx_socket_.reset(new LyXServerSocket(&pimpl_->lyxfunc_,
470 os::internal_path(package().temp_dir() + "/lyxsocket")));
472 // Start the real execution loop.
473 exit_status = pimpl_->application_->exec();
477 // Restore original font resources after Application is destroyed.
478 support::os::restoreFontResources();
484 void LyX::prepareExit()
486 // Set a flag that we do quitting from the program,
487 // so no refreshes are necessary.
490 // close buffers first
491 pimpl_->buffer_list_.closeAll();
493 // do any other cleanup procedures now
494 if (package().temp_dir() != package().system_temp_dir()) {
495 lyxerr[Debug::INFO] << "Deleting tmp dir "
496 << package().temp_dir() << endl;
498 if (!destroyDir(FileName(package().temp_dir()))) {
499 docstring const msg =
500 bformat(_("Unable to remove the temporary directory %1$s"),
501 from_utf8(package().temp_dir()));
502 Alert::warning(_("Unable to remove temporary directory"), msg);
507 if (pimpl_->session_)
508 pimpl_->session_->writeFile();
509 pimpl_->session_.reset();
510 pimpl_->lyx_server_.reset();
511 pimpl_->lyx_socket_.reset();
514 // Kill the application object before exiting. This avoids crashes
515 // when exiting on Linux.
516 if (pimpl_->application_)
517 pimpl_->application_.reset();
521 void LyX::earlyExit(int status)
523 BOOST_ASSERT(pimpl_->application_.get());
524 // LyX::pimpl_::application_ is not initialised at this
525 // point so it's safe to just exit after some cleanup.
531 int LyX::init(int & argc, char * argv[])
533 // check for any spurious extra arguments
534 // other than documents
535 for (int argi = 1; argi < argc ; ++argi) {
536 if (argv[argi][0] == '-') {
538 bformat(_("Wrong command line option `%1$s'. Exiting."),
539 from_utf8(argv[argi]))) << endl;
544 // Initialization of LyX (reads lyxrc and more)
545 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
546 bool success = init();
547 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
551 for (int argi = argc - 1; argi >= 1; --argi) {
552 // get absolute path of file and add ".lyx" to
553 // the filename if necessary
554 pimpl_->files_to_load_.push_back(fileSearch(string(),
555 os::internal_path(to_utf8(from_local8bit(argv[argi]))),
556 "lyx", support::allow_unreadable));
560 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
566 void LyX::loadFiles()
568 vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
569 vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
571 for (; it != end; ++it) {
575 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
576 if (loadLyXFile(buf, *it)) {
577 ErrorList const & el = buf->errorList("Parse");
579 for_each(el.begin(), el.end(),
580 boost::bind(&LyX::printError, this, _1));
583 pimpl_->buffer_list_.release(buf);
588 void LyX::execBatchCommands()
590 // The advantage of doing this here is that the event loop
591 // is already started. So any need for interaction will be
595 // Execute batch commands if available
596 if (batch_command.empty())
599 lyxerr[Debug::INIT] << "About to handle -x '"
600 << batch_command << '\'' << endl;
602 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
606 void LyX::restoreGuiSession()
608 LyXView * view = newLyXView();
610 // if some files were specified at command-line we assume that the
611 // user wants to edit *these* files and not to restore the session.
612 if (!pimpl_->files_to_load_.empty()) {
613 for_each(pimpl_->files_to_load_.begin(),
614 pimpl_->files_to_load_.end(),
615 bind(&LyXView::loadLyXFile, view, _1, true));
616 // clear this list to save a few bytes of RAM
617 pimpl_->files_to_load_.clear();
618 pimpl_->session_->lastOpened().clear();
622 if (!lyxrc.load_session)
625 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
626 // do not add to the lastfile list since these files are restored from
627 // last session, and should be already there (regular files), or should
628 // not be added at all (help files).
629 for_each(lastopened.begin(), lastopened.end(),
630 bind(&LyXView::loadLyXFile, view, _1, false));
632 // clear this list to save a few bytes of RAM
633 pimpl_->session_->lastOpened().clear();
637 LyXView * LyX::newLyXView()
642 // determine windows size and position, from lyxrc and/or session
644 unsigned int width = 690;
645 unsigned int height = 510;
646 // default icon size, will be overwritten by stored session value
647 unsigned int iconSizeXY = 0;
648 bool maximize = false;
650 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
651 width = lyxrc.geometry_width;
652 height = lyxrc.geometry_height;
654 // if lyxrc returns (0,0), then use session info
656 string val = session().sessionInfo().load("WindowWidth");
658 width = convert<unsigned int>(val);
659 val = session().sessionInfo().load("WindowHeight");
661 height = convert<unsigned int>(val);
662 if (session().sessionInfo().load("WindowIsMaximized") == "yes")
664 val = session().sessionInfo().load("IconSizeXY");
666 iconSizeXY = convert<unsigned int>(val);
669 // if user wants to restore window position
672 if (lyxrc.geometry_xysaved) {
673 string val = session().sessionInfo().load("WindowPosX");
675 posx = convert<int>(val);
676 val = session().sessionInfo().load("WindowPosY");
678 posy = convert<int>(val);
681 if (!geometryArg.empty())
687 // create the main window
688 LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximize, iconSizeXY, geometryArg);
696 The SIGHUP signal does not exist on Windows and does not need to be handled.
698 Windows handles SIGFPE and SIGSEGV signals as expected.
700 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
701 cause a new thread to be spawned. This may well result in unexpected
702 behaviour by the single-threaded LyX.
704 SIGTERM signals will come only from another process actually sending
705 that signal using 'raise' in Windows' POSIX compatability layer. It will
706 not come from the general "terminate process" methods that everyone
707 actually uses (and which can't be trapped). Killing an app 'politely' on
708 Windows involves first sending a WM_CLOSE message, something that is
709 caught already by the Qt frontend.
711 For more information see:
713 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
714 ...signals are mostly useless on Windows for a variety of reasons that are
717 'UNIX Application Migration Guide, Chapter 9'
718 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
720 'How To Terminate an Application "Cleanly" in Win32'
721 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
725 static void error_handler(int err_sig)
727 // Throw away any signals other than the first one received.
728 static sig_atomic_t handling_error = false;
731 handling_error = true;
733 // We have received a signal indicating a fatal error, so
734 // try and save the data ASAP.
735 LyX::cref().emergencyCleanup();
737 // These lyxerr calls may or may not work:
739 // Signals are asynchronous, so the main program may be in a very
740 // fragile state when a signal is processed and thus while a signal
741 // handler function executes.
742 // In general, therefore, we should avoid performing any
743 // I/O operations or calling most library and system functions from
746 // This shouldn't matter here, however, as we've already invoked
751 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
755 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
758 lyxerr << "\nlyx: SIGSEGV signal caught\n"
759 "Sorry, you have found a bug in LyX. "
760 "Please read the bug-reporting instructions "
761 "in Help->Introduction and send us a bug report, "
762 "if necessary. Thanks !\nBye." << endl;
770 // Deinstall the signal handlers
772 signal(SIGHUP, SIG_DFL);
774 signal(SIGINT, SIG_DFL);
775 signal(SIGFPE, SIG_DFL);
776 signal(SIGSEGV, SIG_DFL);
777 signal(SIGTERM, SIG_DFL);
780 if (err_sig == SIGSEGV ||
781 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
783 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
792 void LyX::printError(ErrorItem const & ei)
794 docstring tmp = _("LyX: ") + ei.error + char_type(':')
796 std::cerr << to_utf8(tmp) << std::endl;
800 void LyX::initGuiFont()
802 if (lyxrc.roman_font_name.empty())
803 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
805 if (lyxrc.sans_font_name.empty())
806 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
808 if (lyxrc.typewriter_font_name.empty())
809 lyxrc.typewriter_font_name
810 = pimpl_->application_->typewriterFontName();
817 signal(SIGHUP, error_handler);
819 signal(SIGFPE, error_handler);
820 signal(SIGSEGV, error_handler);
821 signal(SIGINT, error_handler);
822 signal(SIGTERM, error_handler);
823 // SIGPIPE can be safely ignored.
825 lyxrc.tempdir_path = package().temp_dir();
826 lyxrc.document_path = package().document_dir();
828 if (lyxrc.template_path.empty()) {
829 lyxrc.template_path = addPath(package().system_support(),
834 // Read configuration files
837 // This one may have been distributed along with LyX.
838 if (!readRcFile("lyxrc.dist"))
841 // Set the language defined by the distributor.
842 //setGuiLanguage(lyxrc.gui_language);
844 // Set the PATH correctly.
845 #if !defined (USE_POSIX_PACKAGING)
846 // Add the directory containing the LyX executable to the path
847 // so that LyX can find things like tex2lyx.
848 if (package().build_support().empty())
849 prependEnvPath("PATH", package().binary_dir());
851 if (!lyxrc.path_prefix.empty())
852 prependEnvPath("PATH", lyxrc.path_prefix);
854 // Check that user LyX directory is ok.
855 if (queryUserLyXDir(package().explicit_user_support()))
856 reconfigureUserLyXDir();
858 // no need for a splash when there is no GUI
863 // This one is generated in user_support directory by lib/configure.py.
864 if (!readRcFile("lyxrc.defaults"))
867 // Query the OS to know what formats are viewed natively
868 formats.setAutoOpen();
870 // Read lyxrc.dist again to be able to override viewer auto-detection.
871 readRcFile("lyxrc.dist");
873 system_lyxrc = lyxrc;
874 system_formats = formats;
875 pimpl_->system_converters_ = pimpl_->converters_;
876 pimpl_->system_movers_ = pimpl_->movers_;
877 system_lcolor = lcolor;
879 // This one is edited through the preferences dialog.
880 if (!readRcFile("preferences"))
883 if (!readEncodingsFile("encodings"))
885 if (!readLanguagesFile("languages"))
889 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
894 // Set the language defined by the user.
895 //setGuiLanguage(lyxrc.gui_language);
898 pimpl_->toplevel_keymap_.reset(new kb_keymap);
899 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
900 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
902 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
905 if (!readUIFile(lyxrc.ui_file))
909 if (lyxerr.debugging(Debug::LYXRC))
912 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
913 if (!lyxrc.path_prefix.empty())
914 prependEnvPath("PATH", lyxrc.path_prefix);
916 FileName const document_path(lyxrc.document_path);
917 if (fs::exists(document_path.toFilesystemEncoding()) &&
918 fs::is_directory(document_path.toFilesystemEncoding()))
919 package().document_dir() = lyxrc.document_path;
921 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path)).absFilename();
922 if (package().temp_dir().empty()) {
923 Alert::error(_("Could not create temporary directory"),
924 bformat(_("Could not create a temporary directory in\n"
925 "%1$s. Make sure that this\n"
926 "path exists and is writable and try again."),
927 from_utf8(lyxrc.tempdir_path)));
928 // createLyXTmpDir() tries sufficiently hard to create a
929 // usable temp dir, so the probability to come here is
930 // close to zero. We therefore don't try to overcome this
931 // problem with e.g. asking the user for a new path and
932 // trying again but simply exit.
936 if (lyxerr.debugging(Debug::INIT)) {
937 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
940 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
941 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
943 // This must happen after package initialization and after lyxrc is
944 // read, therefore it can't be done by a static object.
945 ConverterCache::init();
951 void LyX::defaultKeyBindings(kb_keymap * kbmap)
953 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
954 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
955 kbmap->bind("Up", FuncRequest(LFUN_UP));
956 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
958 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
959 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
960 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
961 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
963 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
964 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
965 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
966 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
968 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
969 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
971 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
972 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
974 // kbmap->bindings to enable the use of the numeric keypad
976 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
977 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
978 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
979 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
980 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
981 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
982 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
983 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
984 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
985 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
986 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
987 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
988 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
989 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
990 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
991 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
992 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
993 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
994 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
995 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
996 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
997 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
998 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
999 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
1003 void LyX::emergencyCleanup() const
1005 // what to do about tmpfiles is non-obvious. we would
1006 // like to delete any we find, but our lyxdir might
1007 // contain documents etc. which might be helpful on
1010 pimpl_->buffer_list_.emergencyWriteAll();
1012 if (pimpl_->lyx_server_)
1013 pimpl_->lyx_server_->emergencyCleanup();
1014 pimpl_->lyx_server_.reset();
1015 pimpl_->lyx_socket_.reset();
1020 void LyX::deadKeyBindings(kb_keymap * kbmap)
1022 // bindKeyings for transparent handling of deadkeys
1023 // The keysyms are gotten from XFree86 X11R6
1024 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1025 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1026 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1027 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1028 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1029 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1030 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1031 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1032 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1033 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1034 // nothing with this name
1035 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1036 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1037 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1038 // nothing with this name either...
1039 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1040 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1041 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1042 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1048 // return true if file does not exist or is older than configure.py.
1049 bool needsUpdate(string const & file)
1051 // We cannot initialize configure_script directly because the package
1052 // is not initialized yet when static objects are constructed.
1053 static string configure_script;
1054 static bool firstrun = true;
1056 configure_script = FileName(addName(
1057 package().system_support(),
1058 "configure.py")).toFilesystemEncoding();
1062 string const absfile = FileName(addName(
1063 package().user_support(), file)).toFilesystemEncoding();
1064 return (! fs::exists(absfile))
1065 || (fs::last_write_time(configure_script)
1066 > fs::last_write_time(absfile));
1072 bool LyX::queryUserLyXDir(bool explicit_userdir)
1074 // Does user directory exist?
1075 string const user_support =
1076 FileName(package().user_support()).toFilesystemEncoding();
1077 if (fs::exists(user_support) && fs::is_directory(user_support)) {
1078 first_start = false;
1080 return needsUpdate("lyxrc.defaults")
1081 || needsUpdate("textclass.lst")
1082 || needsUpdate("packages.lst");
1085 first_start = !explicit_userdir;
1087 // If the user specified explicitly a directory, ask whether
1088 // to create it. If the user says "no", then exit.
1089 if (explicit_userdir &&
1091 _("Missing user LyX directory"),
1092 bformat(_("You have specified a non-existent user "
1093 "LyX directory, %1$s.\n"
1094 "It is needed to keep your own configuration."),
1095 from_utf8(package().user_support())),
1097 _("&Create directory"),
1099 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1100 earlyExit(EXIT_FAILURE);
1103 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1104 from_utf8(package().user_support())))
1107 if (!createDirectory(package().user_support(), 0755)) {
1108 // Failed, so let's exit.
1109 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1111 earlyExit(EXIT_FAILURE);
1118 bool LyX::readRcFile(string const & name)
1120 lyxerr[Debug::INIT] << "About to read " << name << "... ";
1122 FileName const lyxrc_path = libFileSearch(string(), name);
1123 if (!lyxrc_path.empty()) {
1125 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
1127 if (lyxrc.read(lyxrc_path) < 0) {
1128 showFileError(name);
1132 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
1138 // Read the ui file `name'
1139 bool LyX::readUIFile(string const & name, bool include)
1149 struct keyword_item uitags[ui_last - 1] = {
1150 { "include", ui_include },
1151 { "menuset", ui_menuset },
1152 { "toolbar", ui_toolbar },
1153 { "toolbars", ui_toolbars }
1156 // Ensure that a file is read only once (prevents include loops)
1157 static std::list<string> uifiles;
1158 std::list<string>::const_iterator it = uifiles.begin();
1159 std::list<string>::const_iterator end = uifiles.end();
1160 it = std::find(it, end, name);
1162 lyxerr[Debug::INIT] << "UI file '" << name
1163 << "' has been read already. "
1164 << "Is this an include loop?"
1169 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1174 ui_path = libFileSearch("ui", name, "inc");
1175 if (ui_path.empty())
1176 ui_path = libFileSearch("ui",
1177 changeExtension(name, "inc"));
1180 ui_path = libFileSearch("ui", name, "ui");
1182 if (ui_path.empty()) {
1183 lyxerr[Debug::INIT] << "Could not find " << name << endl;
1184 showFileError(name);
1188 uifiles.push_back(name);
1190 lyxerr[Debug::INIT] << "Found " << name
1191 << " in " << ui_path << endl;
1192 LyXLex lex(uitags, ui_last - 1);
1193 lex.setFile(ui_path);
1195 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1199 if (lyxerr.debugging(Debug::PARSER))
1200 lex.printTable(lyxerr);
1202 while (lex.isOK()) {
1203 switch (lex.lex()) {
1206 string const file = lex.getString();
1207 if (!readUIFile(file, true))
1212 menubackend.read(lex);
1216 toolbarbackend.read(lex);
1220 toolbarbackend.readToolbars(lex);
1224 if (!rtrim(lex.getString()).empty())
1225 lex.printError("LyX::ReadUIFile: "
1226 "Unknown menu tag: `$$Token'");
1234 // Read the languages file `name'
1235 bool LyX::readLanguagesFile(string const & name)
1237 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1239 FileName const lang_path = libFileSearch(string(), name);
1240 if (lang_path.empty()) {
1241 showFileError(name);
1244 languages.read(lang_path);
1249 // Read the encodings file `name'
1250 bool LyX::readEncodingsFile(string const & name)
1252 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1254 FileName const enc_path = libFileSearch(string(), name);
1255 if (enc_path.empty()) {
1256 showFileError(name);
1259 encodings.read(enc_path);
1268 /// return the the number of arguments consumed
1269 typedef boost::function<int(string const &, string const &)> cmd_helper;
1271 int parse_dbg(string const & arg, string const &)
1274 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1275 Debug::showTags(lyxerr);
1278 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1280 lyxerr.level(Debug::value(arg));
1281 Debug::showLevel(lyxerr, lyxerr.level());
1286 int parse_help(string const &, string const &)
1289 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1290 "Command line switches (case sensitive):\n"
1291 "\t-help summarize LyX usage\n"
1292 "\t-userdir dir set user directory to dir\n"
1293 "\t-sysdir dir set system directory to dir\n"
1294 "\t-geometry WxH+X+Y set geometry of the main window\n"
1295 "\t-dbg feature[,feature]...\n"
1296 " select the features to debug.\n"
1297 " Type `lyx -dbg' to see the list of features\n"
1298 "\t-x [--execute] command\n"
1299 " where command is a lyx command.\n"
1300 "\t-e [--export] fmt\n"
1301 " where fmt is the export format of choice.\n"
1302 "\t-i [--import] fmt file.xxx\n"
1303 " where fmt is the import format of choice\n"
1304 " and file.xxx is the file to be imported.\n"
1305 "\t-version summarize version and build info\n"
1306 "Check the LyX man page for more details.")) << endl;
1311 int parse_version(string const &, string const &)
1313 lyxerr << "LyX " << lyx_version
1314 << " (" << lyx_release_date << ")" << endl;
1315 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1317 lyxerr << lyx_version_info << endl;
1322 int parse_sysdir(string const & arg, string const &)
1325 Alert::error(_("No system directory"),
1326 _("Missing directory for -sysdir switch"));
1329 cl_system_support = arg;
1333 int parse_userdir(string const & arg, string const &)
1336 Alert::error(_("No user directory"),
1337 _("Missing directory for -userdir switch"));
1340 cl_user_support = arg;
1344 int parse_execute(string const & arg, string const &)
1347 Alert::error(_("Incomplete command"),
1348 _("Missing command string after --execute switch"));
1355 int parse_export(string const & type, string const &)
1358 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1359 "--export switch")) << endl;
1362 batch = "buffer-export " + type;
1367 int parse_import(string const & type, string const & file)
1370 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1371 "--import switch")) << endl;
1375 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1379 batch = "buffer-import " + type + ' ' + file;
1383 int parse_geometry(string const & arg1, string const &)
1386 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1387 // remove also the arg
1390 // don't remove "-geometry"
1399 void LyX::easyParse(int & argc, char * argv[])
1401 std::map<string, cmd_helper> cmdmap;
1403 cmdmap["-dbg"] = parse_dbg;
1404 cmdmap["-help"] = parse_help;
1405 cmdmap["--help"] = parse_help;
1406 cmdmap["-version"] = parse_version;
1407 cmdmap["--version"] = parse_version;
1408 cmdmap["-sysdir"] = parse_sysdir;
1409 cmdmap["-userdir"] = parse_userdir;
1410 cmdmap["-x"] = parse_execute;
1411 cmdmap["--execute"] = parse_execute;
1412 cmdmap["-e"] = parse_export;
1413 cmdmap["--export"] = parse_export;
1414 cmdmap["-i"] = parse_import;
1415 cmdmap["--import"] = parse_import;
1416 cmdmap["-geometry"] = parse_geometry;
1418 for (int i = 1; i < argc; ++i) {
1419 std::map<string, cmd_helper>::const_iterator it
1420 = cmdmap.find(argv[i]);
1422 // don't complain if not found - may be parsed later
1423 if (it == cmdmap.end())
1426 string const arg((i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string());
1427 string const arg2((i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string());
1429 int const remove = 1 + it->second(arg, arg2);
1431 // Now, remove used arguments by shifting
1432 // the following ones remove places down.
1435 for (int j = i; j < argc; ++j)
1436 argv[j] = argv[j + remove];
1441 batch_command = batch;
1445 FuncStatus getStatus(FuncRequest const & action)
1447 return LyX::ref().lyxFunc().getStatus(action);
1451 void dispatch(FuncRequest const & action)
1453 LyX::ref().lyxFunc().dispatch(action);
1457 BufferList & theBufferList()
1459 return LyX::ref().bufferList();
1463 LyXFunc & theLyXFunc()
1465 return LyX::ref().lyxFunc();
1469 LyXServer & theLyXServer()
1471 // FIXME: this should not be use_gui dependent
1472 BOOST_ASSERT(use_gui);
1473 return LyX::ref().server();
1477 LyXServerSocket & theLyXServerSocket()
1479 // FIXME: this should not be use_gui dependent
1480 BOOST_ASSERT(use_gui);
1481 return LyX::ref().socket();
1485 kb_keymap & theTopLevelKeymap()
1487 BOOST_ASSERT(use_gui);
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 IconvProcessor & utf8ToUcs4()
1530 return LyX::ref().iconvProcessor();
1534 Messages & getMessages(std::string const & language)
1536 return LyX::ref().getMessages(language);
1540 Messages & getGuiMessages()
1542 return LyX::ref().getGuiMessages();