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/os.h"
57 #include "support/package.h"
58 #include "support/path.h"
59 #include "support/systemcall.h"
60 #include "support/unicode.h"
62 #include <boost/bind.hpp>
63 #include <boost/filesystem/operations.hpp>
74 using support::addName;
75 using support::addPath;
76 using support::bformat;
77 using support::createDirectory;
78 using support::createLyXTmpDir;
79 using support::destroyDir;
80 using support::FileName;
81 using support::fileSearch;
82 using support::getEnv;
83 using support::i18nLibFileSearch;
84 using support::libFileSearch;
85 using support::package;
86 using support::prependEnvPath;
88 using support::Systemcall;
90 namespace Alert = frontend::Alert;
91 namespace os = support::os;
92 namespace fs = boost::filesystem;
101 #ifndef CXX_GLOBAL_CSTD
108 /// are we using the GUI at all?
110 * We default to true and this is changed to false when the export feature is used.
117 // Filled with the command line arguments "foo" of "-sysdir foo" or
119 string cl_system_support;
120 string cl_user_support;
122 std::string geometryArg;
124 LyX * singleton_ = 0;
126 void showFileError(string const & error)
128 Alert::warning(_("Could not read configuration file"),
129 bformat(_("Error while reading the configuration file\n%1$s.\n"
130 "Please check your installation."), from_utf8(error)));
134 void reconfigureUserLyXDir()
136 string const configure_command = package().configure_command();
138 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
139 support::Path p(package().user_support());
141 one.startscript(Systemcall::Wait, configure_command);
142 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
148 /// The main application class private implementation.
149 struct LyX::Singletons
151 Singletons(): iconv(ucs4_codeset, "UTF-8")
153 // Set the default User Interface language as soon as possible.
154 // The language used will be derived from the environment
156 messages_["GUI"] = Messages();
158 /// our function handler
161 BufferList buffer_list_;
163 boost::scoped_ptr<kb_keymap> toplevel_keymap_;
165 boost::scoped_ptr<LyXServer> lyx_server_;
167 boost::scoped_ptr<LyXServerSocket> lyx_socket_;
169 boost::scoped_ptr<frontend::Application> application_;
170 /// lyx session, containing lastfiles, lastfilepos, and lastopened
171 boost::scoped_ptr<Session> session_;
174 IconvProcessor iconv;
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_;
192 Movers system_movers_;
196 frontend::Application * theApp()
199 return &singleton_->application();
212 BOOST_ASSERT(singleton_);
217 LyX const & LyX::cref()
219 BOOST_ASSERT(singleton_);
228 pimpl_.reset(new Singletons);
233 BufferList & LyX::bufferList()
235 return pimpl_->buffer_list_;
239 BufferList const & LyX::bufferList() const
241 return pimpl_->buffer_list_;
245 Session & LyX::session()
247 BOOST_ASSERT(pimpl_->session_.get());
248 return *pimpl_->session_.get();
252 Session const & LyX::session() const
254 BOOST_ASSERT(pimpl_->session_.get());
255 return *pimpl_->session_.get();
259 LyXFunc & LyX::lyxFunc()
261 return pimpl_->lyxfunc_;
265 LyXFunc const & LyX::lyxFunc() const
267 return pimpl_->lyxfunc_;
271 LyXServer & LyX::server()
273 BOOST_ASSERT(pimpl_->lyx_server_.get());
274 return *pimpl_->lyx_server_.get();
278 LyXServer const & LyX::server() const
280 BOOST_ASSERT(pimpl_->lyx_server_.get());
281 return *pimpl_->lyx_server_.get();
285 LyXServerSocket & LyX::socket()
287 BOOST_ASSERT(pimpl_->lyx_socket_.get());
288 return *pimpl_->lyx_socket_.get();
292 LyXServerSocket const & LyX::socket() const
294 BOOST_ASSERT(pimpl_->lyx_socket_.get());
295 return *pimpl_->lyx_socket_.get();
299 frontend::Application & LyX::application()
301 BOOST_ASSERT(pimpl_->application_.get());
302 return *pimpl_->application_.get();
306 frontend::Application const & LyX::application() const
308 BOOST_ASSERT(pimpl_->application_.get());
309 return *pimpl_->application_.get();
313 kb_keymap & LyX::topLevelKeymap()
315 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
316 return *pimpl_->toplevel_keymap_.get();
320 Converters & LyX::converters()
322 return pimpl_->converters_;
326 Converters & LyX::systemConverters()
328 return pimpl_->system_converters_;
332 IconvProcessor & LyX::iconvProcessor()
334 return pimpl_->iconv;
338 kb_keymap const & LyX::topLevelKeymap() const
340 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
341 return *pimpl_->toplevel_keymap_.get();
345 Messages & LyX::getMessages(std::string const & language)
347 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
349 if (it != pimpl_->messages_.end())
352 std::pair<map<string, Messages>::iterator, bool> result =
353 pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
355 BOOST_ASSERT(result.second);
356 return result.first->second;
360 Messages & LyX::getGuiMessages()
362 return pimpl_->messages_["GUI"];
366 void LyX::setGuiLanguage(std::string const & language)
368 pimpl_->messages_["GUI"] = Messages(language);
372 Buffer const * const LyX::updateInset(InsetBase const * inset) const
377 Buffer const * buffer_ptr = 0;
378 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
379 vector<int>::const_iterator it = view_ids.begin();
380 vector<int>::const_iterator const end = view_ids.end();
381 for (; it != end; ++it) {
383 pimpl_->application_->gui().view(*it).updateInset(inset);
391 int LyX::exec(int & argc, char * argv[])
393 // Here we need to parse the command line. At least
394 // we need to parse for "-dbg" and "-help"
395 easyParse(argc, argv);
397 support::init_package(to_utf8(from_local8bit(argv[0])),
398 cl_system_support, cl_user_support,
399 support::top_build_dir_is_one_level_up);
402 // FIXME: create a ConsoleApplication
403 int exit_status = init(argc, argv);
411 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
416 BufferList::iterator begin = pimpl_->buffer_list_.begin();
417 BufferList::iterator end = pimpl_->buffer_list_.end();
419 bool final_success = false;
420 for (BufferList::iterator I = begin; I != end; ++I) {
422 bool success = false;
423 buf->dispatch(batch_command, &success);
424 final_success |= success;
427 return !final_success;
430 // Force adding of font path _before_ Application is initialized
431 support::os::addFontResources();
433 // Let the frontend parse and remove all arguments that it knows
434 pimpl_->application_.reset(createApplication(argc, argv));
438 // Parse and remove all known arguments in the LyX singleton
439 // Give an error for all remaining ones.
440 int exit_status = init(argc, argv);
442 // Kill the application object before exiting.
443 pimpl_->application_.reset();
450 /* Create a CoreApplication class that will provide the main event loop
451 * and the socket callback registering. With Qt4, only QtCore
452 * library would be needed.
453 * When this is done, a server_mode could be created and the following two
454 * line would be moved out from here.
456 // Note: socket callback must be registered after init(argc, argv)
457 // such that package().temp_dir() is properly initialized.
458 pimpl_->lyx_server_.reset(new LyXServer(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
459 pimpl_->lyx_socket_.reset(new LyXServerSocket(&pimpl_->lyxfunc_,
460 os::internal_path(package().temp_dir() + "/lyxsocket")));
462 // Start the real execution loop.
463 exit_status = pimpl_->application_->exec();
467 // Restore original font resources after Application is destroyed.
468 support::os::restoreFontResources();
474 void LyX::prepareExit()
476 // Set a flag that we do quitting from the program,
477 // so no refreshes are necessary.
480 // close buffers first
481 pimpl_->buffer_list_.closeAll();
483 // do any other cleanup procedures now
484 if (package().temp_dir() != package().system_temp_dir()) {
485 lyxerr[Debug::INFO] << "Deleting tmp dir "
486 << package().temp_dir() << endl;
488 if (!destroyDir(FileName(package().temp_dir()))) {
489 docstring const msg =
490 bformat(_("Unable to remove the temporary directory %1$s"),
491 from_utf8(package().temp_dir()));
492 Alert::warning(_("Unable to remove temporary directory"), msg);
497 if (pimpl_->session_)
498 pimpl_->session_->writeFile();
499 pimpl_->session_.reset();
500 pimpl_->lyx_server_.reset();
501 pimpl_->lyx_socket_.reset();
504 // Kill the application object before exiting. This avoids crashes
505 // when exiting on Linux.
506 if (pimpl_->application_)
507 pimpl_->application_.reset();
511 void LyX::earlyExit(int status)
513 BOOST_ASSERT(pimpl_->application_.get());
514 // LyX::pimpl_::application_ is not initialised at this
515 // point so it's safe to just exit after some cleanup.
521 int LyX::init(int & argc, char * argv[])
523 // check for any spurious extra arguments
524 // other than documents
525 for (int argi = 1; argi < argc ; ++argi) {
526 if (argv[argi][0] == '-') {
528 bformat(_("Wrong command line option `%1$s'. Exiting."),
529 from_utf8(argv[argi]))) << endl;
534 // Initialization of LyX (reads lyxrc and more)
535 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
536 bool success = init();
537 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
541 for (int argi = argc - 1; argi >= 1; --argi) {
542 // get absolute path of file and add ".lyx" to
543 // the filename if necessary
544 pimpl_->files_to_load_.push_back(fileSearch(string(),
545 os::internal_path(to_utf8(from_local8bit(argv[argi]))),
546 "lyx", support::allow_unreadable));
550 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
556 void LyX::loadFiles()
558 vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
559 vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
561 for (; it != end; ++it) {
565 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
566 if (loadLyXFile(buf, *it)) {
567 ErrorList const & el = buf->errorList("Parse");
569 for_each(el.begin(), el.end(),
570 boost::bind(&LyX::printError, this, _1));
573 pimpl_->buffer_list_.release(buf);
578 void LyX::execBatchCommands()
580 // The advantage of doing this here is that the event loop
581 // is already started. So any need for interaction will be
585 // Execute batch commands if available
586 if (batch_command.empty())
589 lyxerr[Debug::INIT] << "About to handle -x '"
590 << batch_command << '\'' << endl;
592 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
596 void LyX::restoreGuiSession()
598 LyXView * view = newLyXView();
600 // if some files were specified at command-line we assume that the
601 // user wants to edit *these* files and not to restore the session.
602 if (!pimpl_->files_to_load_.empty()) {
603 for_each(pimpl_->files_to_load_.begin(),
604 pimpl_->files_to_load_.end(),
605 bind(&LyXView::loadLyXFile, view, _1, true));
606 // clear this list to save a few bytes of RAM
607 pimpl_->files_to_load_.clear();
608 pimpl_->session_->lastOpened().clear();
612 if (!lyxrc.load_session)
615 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
616 // do not add to the lastfile list since these files are restored from
617 // last session, and should be already there (regular files), or should
618 // not be added at all (help files).
619 for_each(lastopened.begin(), lastopened.end(),
620 bind(&LyXView::loadLyXFile, view, _1, false));
622 // clear this list to save a few bytes of RAM
623 pimpl_->session_->lastOpened().clear();
627 LyXView * LyX::newLyXView()
632 // determine windows size and position, from lyxrc and/or session
634 unsigned int width = 690;
635 unsigned int height = 510;
636 // default icon size, will be overwritten by stored session value
637 unsigned int iconSizeXY = 0;
638 bool maximize = false;
640 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
641 width = lyxrc.geometry_width;
642 height = lyxrc.geometry_height;
644 // if lyxrc returns (0,0), then use session info
646 string val = session().sessionInfo().load("WindowWidth");
648 width = convert<unsigned int>(val);
649 val = session().sessionInfo().load("WindowHeight");
651 height = convert<unsigned int>(val);
652 if (session().sessionInfo().load("WindowIsMaximized") == "yes")
654 val = session().sessionInfo().load("IconSizeXY");
656 iconSizeXY = convert<unsigned int>(val);
659 // if user wants to restore window position
662 if (lyxrc.geometry_xysaved) {
663 string val = session().sessionInfo().load("WindowPosX");
665 posx = convert<int>(val);
666 val = session().sessionInfo().load("WindowPosY");
668 posy = convert<int>(val);
671 if (!geometryArg.empty())
677 // create the main window
678 LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximize, iconSizeXY, geometryArg);
686 The SIGHUP signal does not exist on Windows and does not need to be handled.
688 Windows handles SIGFPE and SIGSEGV signals as expected.
690 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
691 cause a new thread to be spawned. This may well result in unexpected
692 behaviour by the single-threaded LyX.
694 SIGTERM signals will come only from another process actually sending
695 that signal using 'raise' in Windows' POSIX compatability layer. It will
696 not come from the general "terminate process" methods that everyone
697 actually uses (and which can't be trapped). Killing an app 'politely' on
698 Windows involves first sending a WM_CLOSE message, something that is
699 caught already by the Qt frontend.
701 For more information see:
703 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
704 ...signals are mostly useless on Windows for a variety of reasons that are
707 'UNIX Application Migration Guide, Chapter 9'
708 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
710 'How To Terminate an Application "Cleanly" in Win32'
711 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
715 static void error_handler(int err_sig)
717 // Throw away any signals other than the first one received.
718 static sig_atomic_t handling_error = false;
721 handling_error = true;
723 // We have received a signal indicating a fatal error, so
724 // try and save the data ASAP.
725 LyX::cref().emergencyCleanup();
727 // These lyxerr calls may or may not work:
729 // Signals are asynchronous, so the main program may be in a very
730 // fragile state when a signal is processed and thus while a signal
731 // handler function executes.
732 // In general, therefore, we should avoid performing any
733 // I/O operations or calling most library and system functions from
736 // This shouldn't matter here, however, as we've already invoked
741 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
745 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
748 lyxerr << "\nlyx: SIGSEGV signal caught\n"
749 "Sorry, you have found a bug in LyX. "
750 "Please read the bug-reporting instructions "
751 "in Help->Introduction and send us a bug report, "
752 "if necessary. Thanks !\nBye." << endl;
760 // Deinstall the signal handlers
762 signal(SIGHUP, SIG_DFL);
764 signal(SIGINT, SIG_DFL);
765 signal(SIGFPE, SIG_DFL);
766 signal(SIGSEGV, SIG_DFL);
767 signal(SIGTERM, SIG_DFL);
770 if (err_sig == SIGSEGV ||
771 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
773 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
782 void LyX::printError(ErrorItem const & ei)
784 docstring tmp = _("LyX: ") + ei.error + char_type(':')
786 std::cerr << to_utf8(tmp) << std::endl;
790 void LyX::initGuiFont()
792 if (lyxrc.roman_font_name.empty())
793 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
795 if (lyxrc.sans_font_name.empty())
796 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
798 if (lyxrc.typewriter_font_name.empty())
799 lyxrc.typewriter_font_name
800 = pimpl_->application_->typewriterFontName();
807 signal(SIGHUP, error_handler);
809 signal(SIGFPE, error_handler);
810 signal(SIGSEGV, error_handler);
811 signal(SIGINT, error_handler);
812 signal(SIGTERM, error_handler);
813 // SIGPIPE can be safely ignored.
815 lyxrc.tempdir_path = package().temp_dir();
816 lyxrc.document_path = package().document_dir();
818 if (lyxrc.template_path.empty()) {
819 lyxrc.template_path = addPath(package().system_support(),
824 // Read configuration files
827 // This one may have been distributed along with LyX.
828 if (!readRcFile("lyxrc.dist"))
831 // Set the language defined by the distributor.
832 //setGuiLanguage(lyxrc.gui_language);
834 // Set the PATH correctly.
835 #if !defined (USE_POSIX_PACKAGING)
836 // Add the directory containing the LyX executable to the path
837 // so that LyX can find things like tex2lyx.
838 if (package().build_support().empty())
839 prependEnvPath("PATH", package().binary_dir());
841 if (!lyxrc.path_prefix.empty())
842 prependEnvPath("PATH", lyxrc.path_prefix);
844 // Check that user LyX directory is ok.
845 if (queryUserLyXDir(package().explicit_user_support()))
846 reconfigureUserLyXDir();
848 // no need for a splash when there is no GUI
853 // This one is generated in user_support directory by lib/configure.py.
854 if (!readRcFile("lyxrc.defaults"))
857 // Query the OS to know what formats are viewed natively
858 formats.setAutoOpen();
860 // Read lyxrc.dist again to be able to override viewer auto-detection.
861 readRcFile("lyxrc.dist");
863 system_lyxrc = lyxrc;
864 system_formats = formats;
865 pimpl_->system_converters_ = pimpl_->converters_;
866 pimpl_->system_movers_ = pimpl_->movers_;
867 system_lcolor = lcolor;
869 // This one is edited through the preferences dialog.
870 if (!readRcFile("preferences"))
873 if (!readEncodingsFile("encodings"))
875 if (!readLanguagesFile("languages"))
879 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
884 // Set the language defined by the user.
885 //setGuiLanguage(lyxrc.gui_language);
888 pimpl_->toplevel_keymap_.reset(new kb_keymap);
889 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
890 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
892 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
895 if (!readUIFile(lyxrc.ui_file))
899 if (lyxerr.debugging(Debug::LYXRC))
902 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
903 if (!lyxrc.path_prefix.empty())
904 prependEnvPath("PATH", lyxrc.path_prefix);
906 FileName const document_path(lyxrc.document_path);
907 if (fs::exists(document_path.toFilesystemEncoding()) &&
908 fs::is_directory(document_path.toFilesystemEncoding()))
909 package().document_dir() = lyxrc.document_path;
911 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path)).absFilename();
912 if (package().temp_dir().empty()) {
913 Alert::error(_("Could not create temporary directory"),
914 bformat(_("Could not create a temporary directory in\n"
915 "%1$s. Make sure that this\n"
916 "path exists and is writable and try again."),
917 from_utf8(lyxrc.tempdir_path)));
918 // createLyXTmpDir() tries sufficiently hard to create a
919 // usable temp dir, so the probability to come here is
920 // close to zero. We therefore don't try to overcome this
921 // problem with e.g. asking the user for a new path and
922 // trying again but simply exit.
926 if (lyxerr.debugging(Debug::INIT)) {
927 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
930 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
931 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
933 // This must happen after package initialization and after lyxrc is
934 // read, therefore it can't be done by a static object.
935 ConverterCache::init();
941 void LyX::defaultKeyBindings(kb_keymap * kbmap)
943 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
944 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
945 kbmap->bind("Up", FuncRequest(LFUN_UP));
946 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
948 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
949 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
950 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
951 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
953 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
954 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
955 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
956 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
958 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
959 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
961 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
962 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
964 // kbmap->bindings to enable the use of the numeric keypad
966 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
967 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
968 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
969 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
970 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
971 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
972 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
973 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
974 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
975 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
976 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
977 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
978 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
979 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
980 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
981 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
982 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
983 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
984 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
985 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
986 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
987 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
988 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
989 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
993 void LyX::emergencyCleanup() const
995 // what to do about tmpfiles is non-obvious. we would
996 // like to delete any we find, but our lyxdir might
997 // contain documents etc. which might be helpful on
1000 pimpl_->buffer_list_.emergencyWriteAll();
1002 if (pimpl_->lyx_server_)
1003 pimpl_->lyx_server_->emergencyCleanup();
1004 pimpl_->lyx_server_.reset();
1005 pimpl_->lyx_socket_.reset();
1010 void LyX::deadKeyBindings(kb_keymap * kbmap)
1012 // bindKeyings for transparent handling of deadkeys
1013 // The keysyms are gotten from XFree86 X11R6
1014 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1015 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1016 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1017 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1018 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1019 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1020 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1021 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1022 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1023 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1024 // nothing with this name
1025 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1026 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1027 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1028 // nothing with this name either...
1029 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1030 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1031 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1032 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1038 // return true if file does not exist or is older than configure.py.
1039 bool needsUpdate(string const & file)
1041 // We cannot initialize configure_script directly because the package
1042 // is not initialized yet when static objects are constructed.
1043 static string configure_script;
1044 static bool firstrun = true;
1046 configure_script = FileName(addName(
1047 package().system_support(),
1048 "configure.py")).toFilesystemEncoding();
1052 string const absfile = FileName(addName(
1053 package().user_support(), file)).toFilesystemEncoding();
1054 return (! fs::exists(absfile))
1055 || (fs::last_write_time(configure_script)
1056 > fs::last_write_time(absfile));
1062 bool LyX::queryUserLyXDir(bool explicit_userdir)
1064 // Does user directory exist?
1065 string const user_support =
1066 FileName(package().user_support()).toFilesystemEncoding();
1067 if (fs::exists(user_support) && fs::is_directory(user_support)) {
1068 first_start = false;
1070 return needsUpdate("lyxrc.defaults")
1071 || needsUpdate("textclass.lst")
1072 || needsUpdate("packages.lst");
1075 first_start = !explicit_userdir;
1077 // If the user specified explicitly a directory, ask whether
1078 // to create it. If the user says "no", then exit.
1079 if (explicit_userdir &&
1081 _("Missing user LyX directory"),
1082 bformat(_("You have specified a non-existent user "
1083 "LyX directory, %1$s.\n"
1084 "It is needed to keep your own configuration."),
1085 from_utf8(package().user_support())),
1087 _("&Create directory"),
1089 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1090 earlyExit(EXIT_FAILURE);
1093 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1094 from_utf8(package().user_support())))
1097 if (!createDirectory(package().user_support(), 0755)) {
1098 // Failed, so let's exit.
1099 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1101 earlyExit(EXIT_FAILURE);
1108 bool LyX::readRcFile(string const & name)
1110 lyxerr[Debug::INIT] << "About to read " << name << "... ";
1112 FileName const lyxrc_path = libFileSearch(string(), name);
1113 if (!lyxrc_path.empty()) {
1115 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
1117 if (lyxrc.read(lyxrc_path) < 0) {
1118 showFileError(name);
1122 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
1128 // Read the ui file `name'
1129 bool LyX::readUIFile(string const & name)
1139 struct keyword_item uitags[ui_last - 1] = {
1140 { "include", ui_include },
1141 { "menuset", ui_menuset },
1142 { "toolbar", ui_toolbar },
1143 { "toolbars", ui_toolbars }
1146 // Ensure that a file is read only once (prevents include loops)
1147 static std::list<string> uifiles;
1148 std::list<string>::const_iterator it = uifiles.begin();
1149 std::list<string>::const_iterator end = uifiles.end();
1150 it = std::find(it, end, name);
1152 lyxerr[Debug::INIT] << "UI file '" << name
1153 << "' has been read already. "
1154 << "Is this an include loop?"
1159 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1161 FileName const ui_path = libFileSearch("ui", name, "ui");
1163 if (ui_path.empty()) {
1164 lyxerr[Debug::INIT] << "Could not find " << name << endl;
1165 showFileError(name);
1168 uifiles.push_back(name);
1170 lyxerr[Debug::INIT] << "Found " << name
1171 << " in " << ui_path << endl;
1172 LyXLex lex(uitags, ui_last - 1);
1173 lex.setFile(ui_path);
1175 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1179 if (lyxerr.debugging(Debug::PARSER))
1180 lex.printTable(lyxerr);
1182 while (lex.isOK()) {
1183 switch (lex.lex()) {
1186 string const file = lex.getString();
1187 if (!readUIFile(file))
1192 menubackend.read(lex);
1196 toolbarbackend.read(lex);
1200 toolbarbackend.readToolbars(lex);
1204 if (!rtrim(lex.getString()).empty())
1205 lex.printError("LyX::ReadUIFile: "
1206 "Unknown menu tag: `$$Token'");
1214 // Read the languages file `name'
1215 bool LyX::readLanguagesFile(string const & name)
1217 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1219 FileName const lang_path = libFileSearch(string(), name);
1220 if (lang_path.empty()) {
1221 showFileError(name);
1224 languages.read(lang_path);
1229 // Read the encodings file `name'
1230 bool LyX::readEncodingsFile(string const & name)
1232 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1234 FileName const enc_path = libFileSearch(string(), name);
1235 if (enc_path.empty()) {
1236 showFileError(name);
1239 encodings.read(enc_path);
1248 /// return the the number of arguments consumed
1249 typedef boost::function<int(string const &, string const &)> cmd_helper;
1251 int parse_dbg(string const & arg, string const &)
1254 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1255 Debug::showTags(lyxerr);
1258 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1260 lyxerr.level(Debug::value(arg));
1261 Debug::showLevel(lyxerr, lyxerr.level());
1266 int parse_help(string const &, string const &)
1269 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1270 "Command line switches (case sensitive):\n"
1271 "\t-help summarize LyX usage\n"
1272 "\t-userdir dir set user directory to dir\n"
1273 "\t-sysdir dir set system directory to dir\n"
1274 "\t-geometry WxH+X+Y set geometry of the main window\n"
1275 "\t-dbg feature[,feature]...\n"
1276 " select the features to debug.\n"
1277 " Type `lyx -dbg' to see the list of features\n"
1278 "\t-x [--execute] command\n"
1279 " where command is a lyx command.\n"
1280 "\t-e [--export] fmt\n"
1281 " where fmt is the export format of choice.\n"
1282 "\t-i [--import] fmt file.xxx\n"
1283 " where fmt is the import format of choice\n"
1284 " and file.xxx is the file to be imported.\n"
1285 "\t-version summarize version and build info\n"
1286 "Check the LyX man page for more details.")) << endl;
1291 int parse_version(string const &, string const &)
1293 lyxerr << "LyX " << lyx_version
1294 << " (" << lyx_release_date << ")" << endl;
1295 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1297 lyxerr << lyx_version_info << endl;
1302 int parse_sysdir(string const & arg, string const &)
1305 lyxerr << to_utf8(_("Missing directory for -sysdir switch")) << endl;
1308 cl_system_support = arg;
1312 int parse_userdir(string const & arg, string const &)
1315 lyxerr << to_utf8(_("Missing directory for -userdir switch")) << endl;
1318 cl_user_support = arg;
1322 int parse_execute(string const & arg, string const &)
1325 lyxerr << to_utf8(_("Missing command string after --execute switch")) << endl;
1332 int parse_export(string const & type, string const &)
1335 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1336 "--export switch")) << endl;
1339 batch = "buffer-export " + type;
1344 int parse_import(string const & type, string const & file)
1347 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1348 "--import switch")) << endl;
1352 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1356 batch = "buffer-import " + type + ' ' + file;
1360 int parse_geometry(string const & arg1, string const &)
1363 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1364 // remove also the arg
1367 // don't remove "-geometry"
1376 void LyX::easyParse(int & argc, char * argv[])
1378 std::map<string, cmd_helper> cmdmap;
1380 cmdmap["-dbg"] = parse_dbg;
1381 cmdmap["-help"] = parse_help;
1382 cmdmap["--help"] = parse_help;
1383 cmdmap["-version"] = parse_version;
1384 cmdmap["--version"] = parse_version;
1385 cmdmap["-sysdir"] = parse_sysdir;
1386 cmdmap["-userdir"] = parse_userdir;
1387 cmdmap["-x"] = parse_execute;
1388 cmdmap["--execute"] = parse_execute;
1389 cmdmap["-e"] = parse_export;
1390 cmdmap["--export"] = parse_export;
1391 cmdmap["-i"] = parse_import;
1392 cmdmap["--import"] = parse_import;
1393 cmdmap["-geometry"] = parse_geometry;
1395 for (int i = 1; i < argc; ++i) {
1396 std::map<string, cmd_helper>::const_iterator it
1397 = cmdmap.find(argv[i]);
1399 // don't complain if not found - may be parsed later
1400 if (it == cmdmap.end())
1403 string const arg((i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string());
1404 string const arg2((i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string());
1406 int const remove = 1 + it->second(arg, arg2);
1408 // Now, remove used arguments by shifting
1409 // the following ones remove places down.
1412 for (int j = i; j < argc; ++j)
1413 argv[j] = argv[j + remove];
1418 batch_command = batch;
1422 FuncStatus getStatus(FuncRequest const & action)
1424 return LyX::ref().lyxFunc().getStatus(action);
1428 void dispatch(FuncRequest const & action)
1430 LyX::ref().lyxFunc().dispatch(action);
1434 BufferList & theBufferList()
1436 return LyX::ref().bufferList();
1440 LyXFunc & theLyXFunc()
1442 return LyX::ref().lyxFunc();
1446 LyXServer & theLyXServer()
1448 // FIXME: this should not be use_gui dependent
1449 BOOST_ASSERT(use_gui);
1450 return LyX::ref().server();
1454 LyXServerSocket & theLyXServerSocket()
1456 // FIXME: this should not be use_gui dependent
1457 BOOST_ASSERT(use_gui);
1458 return LyX::ref().socket();
1462 kb_keymap & theTopLevelKeymap()
1464 BOOST_ASSERT(use_gui);
1465 return LyX::ref().topLevelKeymap();
1469 Converters & theConverters()
1471 return LyX::ref().converters();
1475 Converters & theSystemConverters()
1477 return LyX::ref().systemConverters();
1481 Movers & theMovers()
1483 return LyX::ref().pimpl_->movers_;
1487 Mover const & getMover(std::string const & fmt)
1489 return LyX::ref().pimpl_->movers_(fmt);
1493 void setMover(std::string const & fmt, std::string const & command)
1495 LyX::ref().pimpl_->movers_.set(fmt, command);
1499 Movers & theSystemMovers()
1501 return LyX::ref().pimpl_->system_movers_;
1505 IconvProcessor & utf8ToUcs4()
1507 return LyX::ref().iconvProcessor();
1511 Messages & getMessages(std::string const & language)
1513 return LyX::ref().getMessages(language);
1517 Messages & getGuiMessages()
1519 return LyX::ref().getGuiMessages();