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"
40 #include "ServerSocket.h"
41 #include "TextClassList.h"
42 #include "MenuBackend.h"
45 #include "ToolbarBackend.h"
47 #include "frontends/alert.h"
48 #include "frontends/Application.h"
49 #include "frontends/Dialogs.h"
50 #include "frontends/Gui.h"
51 #include "frontends/LyXView.h"
53 #include "support/environment.h"
54 #include "support/filetools.h"
55 #include "support/lyxlib.h"
56 #include "support/convert.h"
57 #include "support/ExceptionMessage.h"
58 #include "support/os.h"
59 #include "support/Package.h"
60 #include "support/Path.h"
61 #include "support/Systemcall.h"
63 #include <boost/bind.hpp>
64 #include <boost/filesystem/operations.hpp>
76 using support::addName;
77 using support::addPath;
78 using support::bformat;
79 using support::changeExtension;
80 using support::createDirectory;
81 using support::createLyXTmpDir;
82 using support::destroyDir;
83 using support::FileName;
84 using support::fileSearch;
85 using support::getEnv;
86 using support::i18nLibFileSearch;
87 using support::libFileSearch;
88 using support::package;
89 using support::prependEnvPath;
91 using support::Systemcall;
93 namespace Alert = frontend::Alert;
94 namespace os = support::os;
95 namespace fs = boost::filesystem;
100 using std::make_pair;
104 #ifndef CXX_GLOBAL_CSTD
111 /// are we using the GUI at all?
113 * We default to true and this is changed to false when the export feature is used.
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::Path 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.
152 struct LyX::Singletons
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<Server> lyx_server_;
170 boost::scoped_ptr<ServerSocket> lyx_socket_;
172 boost::scoped_ptr<frontend::Application> application_;
173 /// lyx session, containing lastfiles, lastfilepos, and lastopened
174 boost::scoped_ptr<Session> session_;
176 /// Files to load at start.
177 vector<FileName> files_to_load_;
179 /// The messages translators.
180 map<string, Messages> messages_;
182 /// The file converters.
183 Converters converters_;
185 // The system converters copy after reading lyxrc.defaults.
186 Converters system_converters_;
192 Movers system_movers_;
196 frontend::Application * theApp()
199 return singleton_->pimpl_->application_.get();
212 BOOST_ASSERT(singleton_);
217 LyX const & LyX::cref()
219 BOOST_ASSERT(singleton_);
228 pimpl_.reset(new Singletons);
232 BufferList & LyX::bufferList()
234 return pimpl_->buffer_list_;
238 BufferList const & LyX::bufferList() const
240 return pimpl_->buffer_list_;
244 Session & LyX::session()
246 BOOST_ASSERT(pimpl_->session_.get());
247 return *pimpl_->session_.get();
251 Session const & LyX::session() const
253 BOOST_ASSERT(pimpl_->session_.get());
254 return *pimpl_->session_.get();
258 LyXFunc & LyX::lyxFunc()
260 return pimpl_->lyxfunc_;
264 LyXFunc const & LyX::lyxFunc() const
266 return pimpl_->lyxfunc_;
270 Server & LyX::server()
272 BOOST_ASSERT(pimpl_->lyx_server_.get());
273 return *pimpl_->lyx_server_.get();
277 Server const & LyX::server() const
279 BOOST_ASSERT(pimpl_->lyx_server_.get());
280 return *pimpl_->lyx_server_.get();
284 ServerSocket & LyX::socket()
286 BOOST_ASSERT(pimpl_->lyx_socket_.get());
287 return *pimpl_->lyx_socket_.get();
291 ServerSocket const & LyX::socket() const
293 BOOST_ASSERT(pimpl_->lyx_socket_.get());
294 return *pimpl_->lyx_socket_.get();
298 frontend::Application & LyX::application()
300 BOOST_ASSERT(pimpl_->application_.get());
301 return *pimpl_->application_.get();
305 frontend::Application const & LyX::application() const
307 BOOST_ASSERT(pimpl_->application_.get());
308 return *pimpl_->application_.get();
312 KeyMap & LyX::topLevelKeymap()
314 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
315 return *pimpl_->toplevel_keymap_.get();
319 Converters & LyX::converters()
321 return pimpl_->converters_;
325 Converters & LyX::systemConverters()
327 return pimpl_->system_converters_;
331 KeyMap const & LyX::topLevelKeymap() const
333 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
334 return *pimpl_->toplevel_keymap_.get();
338 Messages & LyX::getMessages(std::string const & language)
340 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
342 if (it != pimpl_->messages_.end())
345 std::pair<map<string, Messages>::iterator, bool> result =
346 pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
348 BOOST_ASSERT(result.second);
349 return result.first->second;
353 Messages & LyX::getGuiMessages()
355 return pimpl_->messages_["GUI"];
359 void LyX::setGuiLanguage(std::string const & language)
361 pimpl_->messages_["GUI"] = Messages(language);
365 Buffer const * const LyX::updateInset(Inset const * inset) const
367 if (quitting || !inset)
370 Buffer const * buffer_ptr = 0;
371 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
372 vector<int>::const_iterator it = view_ids.begin();
373 vector<int>::const_iterator const end = view_ids.end();
374 for (; it != end; ++it) {
376 pimpl_->application_->gui().view(*it).updateInset(inset);
384 void LyX::hideDialogs(std::string const & name, Inset * inset) const
386 if (quitting || !use_gui)
389 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
390 vector<int>::const_iterator it = view_ids.begin();
391 vector<int>::const_iterator const end = view_ids.end();
392 for (; it != end; ++it)
393 pimpl_->application_->gui().view(*it).getDialogs().
398 int LyX::exec(int & argc, char * argv[])
400 // Here we need to parse the command line. At least
401 // we need to parse for "-dbg" and "-help"
402 easyParse(argc, argv);
404 try { support::init_package(to_utf8(from_local8bit(argv[0])),
405 cl_system_support, cl_user_support,
406 support::top_build_dir_is_one_level_up);
407 } catch (support::ExceptionMessage const & message) {
408 if (message.type_ == support::ErrorException) {
409 Alert::error(message.title_, message.details_);
411 } else if (message.type_ == support::WarningException) {
412 Alert::warning(message.title_, message.details_);
416 // Reinit the messages machinery in case package() knows
417 // something interesting about the locale directory.
421 // FIXME: create a ConsoleApplication
422 int exit_status = init(argc, argv);
430 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
435 BufferList::iterator begin = pimpl_->buffer_list_.begin();
436 BufferList::iterator end = pimpl_->buffer_list_.end();
438 bool final_success = false;
439 for (BufferList::iterator I = begin; I != end; ++I) {
441 bool success = false;
442 buf->dispatch(batch_command, &success);
443 final_success |= success;
446 return !final_success;
449 // Force adding of font path _before_ Application is initialized
450 support::os::addFontResources();
452 // Let the frontend parse and remove all arguments that it knows
453 pimpl_->application_.reset(createApplication(argc, argv));
457 // Parse and remove all known arguments in the LyX singleton
458 // Give an error for all remaining ones.
459 int exit_status = init(argc, argv);
461 // Kill the application object before exiting.
462 pimpl_->application_.reset();
469 /* Create a CoreApplication class that will provide the main event loop
470 * and the socket callback registering. With Qt4, only QtCore
471 * library would be needed.
472 * When this is done, a server_mode could be created and the following two
473 * line would be moved out from here.
475 // Note: socket callback must be registered after init(argc, argv)
476 // such that package().temp_dir() is properly initialized.
477 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
478 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
479 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
481 // Start the real execution loop.
482 exit_status = pimpl_->application_->exec();
486 // Restore original font resources after Application is destroyed.
487 support::os::restoreFontResources();
493 void LyX::prepareExit()
495 // Set a flag that we do quitting from the program,
496 // so no refreshes are necessary.
499 // close buffers first
500 pimpl_->buffer_list_.closeAll();
502 // do any other cleanup procedures now
503 if (package().temp_dir() != package().system_temp_dir()) {
504 LYXERR(Debug::INFO) << "Deleting tmp dir "
505 << package().temp_dir().absFilename() << endl;
507 if (!destroyDir(package().temp_dir())) {
508 docstring const msg =
509 bformat(_("Unable to remove the temporary directory %1$s"),
510 from_utf8(package().temp_dir().absFilename()));
511 Alert::warning(_("Unable to remove temporary directory"), msg);
516 if (pimpl_->session_)
517 pimpl_->session_->writeFile();
518 pimpl_->session_.reset();
519 pimpl_->lyx_server_.reset();
520 pimpl_->lyx_socket_.reset();
523 // Kill the application object before exiting. This avoids crashes
524 // when exiting on Linux.
525 if (pimpl_->application_)
526 pimpl_->application_.reset();
530 void LyX::earlyExit(int status)
532 BOOST_ASSERT(pimpl_->application_.get());
533 // LyX::pimpl_::application_ is not initialised at this
534 // point so it's safe to just exit after some cleanup.
540 int LyX::init(int & argc, char * argv[])
542 // check for any spurious extra arguments
543 // other than documents
544 for (int argi = 1; argi < argc ; ++argi) {
545 if (argv[argi][0] == '-') {
547 bformat(_("Wrong command line option `%1$s'. Exiting."),
548 from_utf8(argv[argi]))) << endl;
553 // Initialization of LyX (reads lyxrc and more)
554 LYXERR(Debug::INIT) << "Initializing LyX::init..." << endl;
555 bool success = init();
556 LYXERR(Debug::INIT) << "Initializing LyX::init...done" << endl;
560 for (int argi = argc - 1; argi >= 1; --argi) {
561 // get absolute path of file and add ".lyx" to
562 // the filename if necessary
563 pimpl_->files_to_load_.push_back(fileSearch(string(),
564 os::internal_path(to_utf8(from_local8bit(argv[argi]))),
565 "lyx", support::allow_unreadable));
569 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
575 void LyX::addFileToLoad(FileName const & fname)
577 vector<FileName>::const_iterator cit = std::find(
578 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
581 if (cit == pimpl_->files_to_load_.end())
582 pimpl_->files_to_load_.push_back(fname);
586 void LyX::loadFiles()
588 vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
589 vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
591 for (; it != end; ++it) {
595 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
596 if (loadLyXFile(buf, *it)) {
597 ErrorList const & el = buf->errorList("Parse");
599 for_each(el.begin(), el.end(),
600 boost::bind(&LyX::printError, this, _1));
603 pimpl_->buffer_list_.release(buf);
608 void LyX::execBatchCommands()
610 // The advantage of doing this here is that the event loop
611 // is already started. So any need for interaction will be
615 // Execute batch commands if available
616 if (batch_command.empty())
619 LYXERR(Debug::INIT) << "About to handle -x '"
620 << batch_command << '\'' << endl;
622 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
626 void LyX::restoreGuiSession()
628 LyXView * view = newLyXView();
630 // if some files were specified at command-line we assume that the
631 // user wants to edit *these* files and not to restore the session.
632 if (!pimpl_->files_to_load_.empty()) {
633 for_each(pimpl_->files_to_load_.begin(),
634 pimpl_->files_to_load_.end(),
635 bind(&LyXView::loadLyXFile, view, _1, true, false, false));
636 // clear this list to save a few bytes of RAM
637 pimpl_->files_to_load_.clear();
638 pimpl_->session_->lastOpened().clear();
642 if (!lyxrc.load_session)
645 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
646 // do not add to the lastfile list since these files are restored from
647 // last session, and should be already there (regular files), or should
648 // not be added at all (help files).
649 for_each(lastopened.begin(), lastopened.end(),
650 bind(&LyXView::loadLyXFile, view, _1, false, false, false));
652 // clear this list to save a few bytes of RAM
653 pimpl_->session_->lastOpened().clear();
657 LyXView * LyX::newLyXView()
662 // determine windows size and position, from lyxrc and/or session
664 unsigned int width = 690;
665 unsigned int height = 510;
666 // default icon size, will be overwritten by stored session value
667 unsigned int iconSizeXY = 0;
668 int maximized = LyXView::NotMaximized;
670 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
671 width = lyxrc.geometry_width;
672 height = lyxrc.geometry_height;
674 // if lyxrc returns (0,0), then use session info
676 string val = session().sessionInfo().load("WindowWidth");
678 width = convert<unsigned int>(val);
679 val = session().sessionInfo().load("WindowHeight");
681 height = convert<unsigned int>(val);
682 val = session().sessionInfo().load("WindowMaximized");
684 maximized = convert<int>(val);
685 val = session().sessionInfo().load("IconSizeXY");
687 iconSizeXY = convert<unsigned int>(val);
690 // if user wants to restore window position
693 if (lyxrc.geometry_xysaved) {
694 string val = session().sessionInfo().load("WindowPosX");
696 posx = convert<int>(val);
697 val = session().sessionInfo().load("WindowPosY");
699 posy = convert<int>(val);
702 if (!geometryArg.empty())
708 // create the main window
709 LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximized, iconSizeXY, geometryArg);
717 The SIGHUP signal does not exist on Windows and does not need to be handled.
719 Windows handles SIGFPE and SIGSEGV signals as expected.
721 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
722 cause a new thread to be spawned. This may well result in unexpected
723 behaviour by the single-threaded LyX.
725 SIGTERM signals will come only from another process actually sending
726 that signal using 'raise' in Windows' POSIX compatability layer. It will
727 not come from the general "terminate process" methods that everyone
728 actually uses (and which can't be trapped). Killing an app 'politely' on
729 Windows involves first sending a WM_CLOSE message, something that is
730 caught already by the Qt frontend.
732 For more information see:
734 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
735 ...signals are mostly useless on Windows for a variety of reasons that are
738 'UNIX Application Migration Guide, Chapter 9'
739 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
741 'How To Terminate an Application "Cleanly" in Win32'
742 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
746 static void error_handler(int err_sig)
748 // Throw away any signals other than the first one received.
749 static sig_atomic_t handling_error = false;
752 handling_error = true;
754 // We have received a signal indicating a fatal error, so
755 // try and save the data ASAP.
756 LyX::cref().emergencyCleanup();
758 // These lyxerr calls may or may not work:
760 // Signals are asynchronous, so the main program may be in a very
761 // fragile state when a signal is processed and thus while a signal
762 // handler function executes.
763 // In general, therefore, we should avoid performing any
764 // I/O operations or calling most library and system functions from
767 // This shouldn't matter here, however, as we've already invoked
772 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
776 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
779 lyxerr << "\nlyx: SIGSEGV signal caught\n"
780 "Sorry, you have found a bug in LyX. "
781 "Please read the bug-reporting instructions "
782 "in Help->Introduction and send us a bug report, "
783 "if necessary. Thanks !\nBye." << endl;
791 // Deinstall the signal handlers
793 signal(SIGHUP, SIG_DFL);
795 signal(SIGINT, SIG_DFL);
796 signal(SIGFPE, SIG_DFL);
797 signal(SIGSEGV, SIG_DFL);
798 signal(SIGTERM, SIG_DFL);
801 if (err_sig == SIGSEGV ||
802 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
804 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
813 void LyX::printError(ErrorItem const & ei)
815 docstring tmp = _("LyX: ") + ei.error + char_type(':')
817 std::cerr << to_utf8(tmp) << std::endl;
821 void LyX::initGuiFont()
823 if (lyxrc.roman_font_name.empty())
824 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
826 if (lyxrc.sans_font_name.empty())
827 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
829 if (lyxrc.typewriter_font_name.empty())
830 lyxrc.typewriter_font_name
831 = pimpl_->application_->typewriterFontName();
838 signal(SIGHUP, error_handler);
840 signal(SIGFPE, error_handler);
841 signal(SIGSEGV, error_handler);
842 signal(SIGINT, error_handler);
843 signal(SIGTERM, error_handler);
844 // SIGPIPE can be safely ignored.
846 lyxrc.tempdir_path = package().temp_dir().absFilename();
847 lyxrc.document_path = package().document_dir().absFilename();
849 if (lyxrc.template_path.empty()) {
850 lyxrc.template_path = addPath(package().system_support().absFilename(),
855 // Read configuration files
858 // This one may have been distributed along with LyX.
859 if (!readRcFile("lyxrc.dist"))
862 // Set the language defined by the distributor.
863 //setGuiLanguage(lyxrc.gui_language);
865 // Set the PATH correctly.
866 #if !defined (USE_POSIX_PACKAGING)
867 // Add the directory containing the LyX executable to the path
868 // so that LyX can find things like tex2lyx.
869 if (package().build_support().empty())
870 prependEnvPath("PATH", package().binary_dir().absFilename());
872 if (!lyxrc.path_prefix.empty())
873 prependEnvPath("PATH", lyxrc.path_prefix);
875 // Check that user LyX directory is ok.
876 if (queryUserLyXDir(package().explicit_user_support()))
877 reconfigureUserLyXDir();
879 // no need for a splash when there is no GUI
884 // This one is generated in user_support directory by lib/configure.py.
885 if (!readRcFile("lyxrc.defaults"))
888 // Query the OS to know what formats are viewed natively
889 formats.setAutoOpen();
891 // Read lyxrc.dist again to be able to override viewer auto-detection.
892 readRcFile("lyxrc.dist");
894 system_lyxrc = lyxrc;
895 system_formats = formats;
896 pimpl_->system_converters_ = pimpl_->converters_;
897 pimpl_->system_movers_ = pimpl_->movers_;
898 system_lcolor = lcolor;
900 // This one is edited through the preferences dialog.
901 if (!readRcFile("preferences"))
904 if (!readEncodingsFile("encodings", "unicodesymbols"))
906 if (!readLanguagesFile("languages"))
910 LYXERR(Debug::INIT) << "Reading layouts..." << endl;
915 // Set the language defined by the user.
916 //setGuiLanguage(lyxrc.gui_language);
919 pimpl_->toplevel_keymap_.reset(new KeyMap);
920 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
921 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
923 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
926 if (!readUIFile(lyxrc.ui_file))
930 if (lyxerr.debugging(Debug::LYXRC))
933 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
934 if (!lyxrc.path_prefix.empty())
935 prependEnvPath("PATH", lyxrc.path_prefix);
937 FileName const document_path(lyxrc.document_path);
938 if (fs::exists(document_path.toFilesystemEncoding()) &&
939 fs::is_directory(document_path.toFilesystemEncoding()))
940 package().document_dir() = document_path;
942 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
943 if (package().temp_dir().empty()) {
944 Alert::error(_("Could not create temporary directory"),
945 bformat(_("Could not create a temporary directory in\n"
946 "%1$s. Make sure that this\n"
947 "path exists and is writable and try again."),
948 from_utf8(lyxrc.tempdir_path)));
949 // createLyXTmpDir() tries sufficiently hard to create a
950 // usable temp dir, so the probability to come here is
951 // close to zero. We therefore don't try to overcome this
952 // problem with e.g. asking the user for a new path and
953 // trying again but simply exit.
957 LYXERR(Debug::INIT) << "LyX tmp dir: `"
958 << package().temp_dir().absFilename()
961 LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
962 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
964 // This must happen after package initialization and after lyxrc is
965 // read, therefore it can't be done by a static object.
966 ConverterCache::init();
972 void LyX::defaultKeyBindings(KeyMap * kbmap)
974 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
975 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
976 kbmap->bind("Up", FuncRequest(LFUN_UP));
977 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
979 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
980 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
981 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
982 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
984 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
985 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
986 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
987 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
989 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
990 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
992 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
993 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
995 // kbmap->bindings to enable the use of the numeric keypad
997 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
998 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
999 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
1000 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
1001 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
1002 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
1003 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
1004 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
1005 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
1006 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
1007 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
1008 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
1009 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
1010 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
1011 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
1012 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
1013 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
1014 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
1015 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
1016 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
1017 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
1018 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
1019 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
1020 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
1024 void LyX::emergencyCleanup() const
1026 // what to do about tmpfiles is non-obvious. we would
1027 // like to delete any we find, but our lyxdir might
1028 // contain documents etc. which might be helpful on
1031 pimpl_->buffer_list_.emergencyWriteAll();
1033 if (pimpl_->lyx_server_)
1034 pimpl_->lyx_server_->emergencyCleanup();
1035 pimpl_->lyx_server_.reset();
1036 pimpl_->lyx_socket_.reset();
1041 void LyX::deadKeyBindings(KeyMap * kbmap)
1043 // bindKeyings for transparent handling of deadkeys
1044 // The keysyms are gotten from XFree86 X11R6
1045 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1046 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1047 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1048 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1049 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1050 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1051 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1052 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1053 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1054 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1055 // nothing with this name
1056 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1057 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1058 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1059 // nothing with this name either...
1060 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1061 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1062 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1063 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1069 // return true if file does not exist or is older than configure.py.
1070 bool needsUpdate(string const & file)
1072 // We cannot initialize configure_script directly because the package
1073 // is not initialized yet when static objects are constructed.
1074 static string configure_script;
1075 static bool firstrun = true;
1077 configure_script = FileName(addName(
1078 package().system_support().absFilename(),
1079 "configure.py")).toFilesystemEncoding();
1083 string const absfile = FileName(addName(
1084 package().user_support().absFilename(), file)).toFilesystemEncoding();
1085 return (! fs::exists(absfile))
1086 || (fs::last_write_time(configure_script)
1087 > fs::last_write_time(absfile));
1093 bool LyX::queryUserLyXDir(bool explicit_userdir)
1095 // Does user directory exist?
1096 string const user_support =
1097 package().user_support().toFilesystemEncoding();
1098 if (fs::exists(user_support) && fs::is_directory(user_support)) {
1099 first_start = false;
1101 return needsUpdate("lyxrc.defaults")
1102 || needsUpdate("textclass.lst")
1103 || needsUpdate("packages.lst");
1106 first_start = !explicit_userdir;
1108 // If the user specified explicitly a directory, ask whether
1109 // to create it. If the user says "no", then exit.
1110 if (explicit_userdir &&
1112 _("Missing user LyX directory"),
1113 bformat(_("You have specified a non-existent user "
1114 "LyX directory, %1$s.\n"
1115 "It is needed to keep your own configuration."),
1116 from_utf8(package().user_support().absFilename())),
1118 _("&Create directory"),
1120 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1121 earlyExit(EXIT_FAILURE);
1124 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1125 from_utf8(package().user_support().absFilename())))
1128 if (!createDirectory(package().user_support(), 0755)) {
1129 // Failed, so let's exit.
1130 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1132 earlyExit(EXIT_FAILURE);
1139 bool LyX::readRcFile(string const & name)
1141 LYXERR(Debug::INIT) << "About to read " << name << "... ";
1143 FileName const lyxrc_path = libFileSearch(string(), name);
1144 if (!lyxrc_path.empty()) {
1146 LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
1148 if (lyxrc.read(lyxrc_path) < 0) {
1149 showFileError(name);
1153 LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
1159 // Read the ui file `name'
1160 bool LyX::readUIFile(string const & name, bool include)
1170 struct keyword_item uitags[ui_last - 1] = {
1171 { "include", ui_include },
1172 { "menuset", ui_menuset },
1173 { "toolbars", ui_toolbars },
1174 { "toolbarset", ui_toolbarset }
1177 // Ensure that a file is read only once (prevents include loops)
1178 static std::list<string> uifiles;
1179 std::list<string>::const_iterator it = uifiles.begin();
1180 std::list<string>::const_iterator end = uifiles.end();
1181 it = std::find(it, end, name);
1183 LYXERR(Debug::INIT) << "UI file '" << name
1184 << "' has been read already. "
1185 << "Is this an include loop?"
1190 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1195 ui_path = libFileSearch("ui", name, "inc");
1196 if (ui_path.empty())
1197 ui_path = libFileSearch("ui",
1198 changeExtension(name, "inc"));
1201 ui_path = libFileSearch("ui", name, "ui");
1203 if (ui_path.empty()) {
1204 LYXERR(Debug::INIT) << "Could not find " << name << endl;
1205 showFileError(name);
1209 uifiles.push_back(name);
1211 LYXERR(Debug::INIT) << "Found " << name
1212 << " in " << ui_path << endl;
1213 Lexer lex(uitags, ui_last - 1);
1214 lex.setFile(ui_path);
1216 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1220 if (lyxerr.debugging(Debug::PARSER))
1221 lex.printTable(lyxerr);
1223 while (lex.isOK()) {
1224 switch (lex.lex()) {
1227 string const file = lex.getString();
1228 if (!readUIFile(file, true))
1233 menubackend.read(lex);
1237 toolbarbackend.readToolbars(lex);
1241 toolbarbackend.readToolbarSettings(lex);
1245 if (!rtrim(lex.getString()).empty())
1246 lex.printError("LyX::ReadUIFile: "
1247 "Unknown menu tag: `$$Token'");
1255 // Read the languages file `name'
1256 bool LyX::readLanguagesFile(string const & name)
1258 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1260 FileName const lang_path = libFileSearch(string(), name);
1261 if (lang_path.empty()) {
1262 showFileError(name);
1265 languages.read(lang_path);
1270 // Read the encodings file `name'
1271 bool LyX::readEncodingsFile(string const & enc_name,
1272 string const & symbols_name)
1274 LYXERR(Debug::INIT) << "About to read " << enc_name << " and "
1275 << symbols_name << "..." << endl;
1277 FileName const symbols_path = libFileSearch(string(), symbols_name);
1278 if (symbols_path.empty()) {
1279 showFileError(symbols_name);
1283 FileName const enc_path = libFileSearch(string(), enc_name);
1284 if (enc_path.empty()) {
1285 showFileError(enc_name);
1288 encodings.read(enc_path, symbols_path);
1297 /// return the the number of arguments consumed
1298 typedef boost::function<int(string const &, string const &)> cmd_helper;
1300 int parse_dbg(string const & arg, string const &)
1303 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1304 Debug::showTags(lyxerr);
1307 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1309 lyxerr.level(Debug::value(arg));
1310 Debug::showLevel(lyxerr, lyxerr.level());
1315 int parse_help(string const &, string const &)
1318 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1319 "Command line switches (case sensitive):\n"
1320 "\t-help summarize LyX usage\n"
1321 "\t-userdir dir set user directory to dir\n"
1322 "\t-sysdir dir set system directory to dir\n"
1323 "\t-geometry WxH+X+Y set geometry of the main window\n"
1324 "\t-dbg feature[,feature]...\n"
1325 " select the features to debug.\n"
1326 " Type `lyx -dbg' to see the list of features\n"
1327 "\t-x [--execute] command\n"
1328 " where command is a lyx command.\n"
1329 "\t-e [--export] fmt\n"
1330 " where fmt is the export format of choice.\n"
1331 "\t-i [--import] fmt file.xxx\n"
1332 " where fmt is the import format of choice\n"
1333 " and file.xxx is the file to be imported.\n"
1334 "\t-version summarize version and build info\n"
1335 "Check the LyX man page for more details.")) << endl;
1340 int parse_version(string const &, string const &)
1342 lyxerr << "LyX " << lyx_version
1343 << " (" << lyx_release_date << ")" << endl;
1344 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1346 lyxerr << lyx_version_info << endl;
1351 int parse_sysdir(string const & arg, string const &)
1354 Alert::error(_("No system directory"),
1355 _("Missing directory for -sysdir switch"));
1358 cl_system_support = arg;
1362 int parse_userdir(string const & arg, string const &)
1365 Alert::error(_("No user directory"),
1366 _("Missing directory for -userdir switch"));
1369 cl_user_support = arg;
1373 int parse_execute(string const & arg, string const &)
1376 Alert::error(_("Incomplete command"),
1377 _("Missing command string after --execute switch"));
1384 int parse_export(string const & type, string const &)
1387 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1388 "--export switch")) << endl;
1391 batch = "buffer-export " + type;
1396 int parse_import(string const & type, string const & file)
1399 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1400 "--import switch")) << endl;
1404 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1408 batch = "buffer-import " + type + ' ' + file;
1412 int parse_geometry(string const & arg1, string const &)
1415 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1416 // remove also the arg
1419 // don't remove "-geometry"
1428 void LyX::easyParse(int & argc, char * argv[])
1430 std::map<string, cmd_helper> cmdmap;
1432 cmdmap["-dbg"] = parse_dbg;
1433 cmdmap["-help"] = parse_help;
1434 cmdmap["--help"] = parse_help;
1435 cmdmap["-version"] = parse_version;
1436 cmdmap["--version"] = parse_version;
1437 cmdmap["-sysdir"] = parse_sysdir;
1438 cmdmap["-userdir"] = parse_userdir;
1439 cmdmap["-x"] = parse_execute;
1440 cmdmap["--execute"] = parse_execute;
1441 cmdmap["-e"] = parse_export;
1442 cmdmap["--export"] = parse_export;
1443 cmdmap["-i"] = parse_import;
1444 cmdmap["--import"] = parse_import;
1445 cmdmap["-geometry"] = parse_geometry;
1447 for (int i = 1; i < argc; ++i) {
1448 std::map<string, cmd_helper>::const_iterator it
1449 = cmdmap.find(argv[i]);
1451 // don't complain if not found - may be parsed later
1452 if (it == cmdmap.end())
1455 string const arg((i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string());
1456 string const arg2((i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string());
1458 int const remove = 1 + it->second(arg, arg2);
1460 // Now, remove used arguments by shifting
1461 // the following ones remove places down.
1464 for (int j = i; j < argc; ++j)
1465 argv[j] = argv[j + remove];
1470 batch_command = batch;
1474 FuncStatus getStatus(FuncRequest const & action)
1476 return LyX::ref().lyxFunc().getStatus(action);
1480 void dispatch(FuncRequest const & action)
1482 LyX::ref().lyxFunc().dispatch(action);
1486 BufferList & theBufferList()
1488 return LyX::ref().bufferList();
1492 LyXFunc & theLyXFunc()
1494 return LyX::ref().lyxFunc();
1498 Server & theServer()
1500 // FIXME: this should not be use_gui dependent
1501 BOOST_ASSERT(use_gui);
1502 return LyX::ref().server();
1506 ServerSocket & theServerSocket()
1508 // FIXME: this should not be use_gui dependent
1509 BOOST_ASSERT(use_gui);
1510 return LyX::ref().socket();
1514 KeyMap & theTopLevelKeymap()
1516 BOOST_ASSERT(use_gui);
1517 return LyX::ref().topLevelKeymap();
1521 Converters & theConverters()
1523 return LyX::ref().converters();
1527 Converters & theSystemConverters()
1529 return LyX::ref().systemConverters();
1533 Movers & theMovers()
1535 return LyX::ref().pimpl_->movers_;
1539 Mover const & getMover(std::string const & fmt)
1541 return LyX::ref().pimpl_->movers_(fmt);
1545 void setMover(std::string const & fmt, std::string const & command)
1547 LyX::ref().pimpl_->movers_.set(fmt, command);
1551 Movers & theSystemMovers()
1553 return LyX::ref().pimpl_->system_movers_;
1557 Messages & getMessages(std::string const & language)
1559 return LyX::ref().getMessages(language);
1563 Messages & getGuiMessages()
1565 return LyX::ref().getGuiMessages();