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"
25 #include "CutAndPaste.h"
28 #include "ErrorList.h"
36 #include "LyXAction.h"
40 #include "ModuleList.h"
42 #include "ServerSocket.h"
43 #include "TextClassList.h"
44 #include "MenuBackend.h"
47 #include "ToolbarBackend.h"
49 #include "frontends/alert.h"
50 #include "frontends/Application.h"
51 #include "frontends/Dialogs.h"
52 #include "frontends/Gui.h"
53 #include "frontends/LyXView.h"
55 #include "support/environment.h"
56 #include "support/filetools.h"
57 #include "support/lyxlib.h"
58 #include "support/convert.h"
59 #include "support/ExceptionMessage.h"
60 #include "support/os.h"
61 #include "support/Package.h"
62 #include "support/Path.h"
63 #include "support/Systemcall.h"
65 #include <boost/bind.hpp>
81 #ifndef CXX_GLOBAL_CSTD
89 using support::addName;
90 using support::addPath;
91 using support::bformat;
92 using support::changeExtension;
93 using support::createLyXTmpDir;
94 using support::FileName;
95 using support::fileSearch;
96 using support::getEnv;
97 using support::i18nLibFileSearch;
98 using support::libFileSearch;
99 using support::package;
100 using support::prependEnvPath;
101 using support::rtrim;
102 using support::Systemcall;
103 using frontend::LyXView;
105 namespace Alert = frontend::Alert;
106 namespace os = support::os;
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.
116 bool quitting; // flag, that we are quitting the program
120 // Filled with the command line arguments "foo" of "-sysdir foo" or
122 string cl_system_support;
123 string cl_user_support;
125 std::string geometryArg;
127 LyX * singleton_ = 0;
129 void showFileError(string const & error)
131 Alert::warning(_("Could not read configuration file"),
132 bformat(_("Error while reading the configuration file\n%1$s.\n"
133 "Please check your installation."), from_utf8(error)));
137 void reconfigureUserLyXDir()
139 string const configure_command = package().configure_command();
141 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
142 support::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<CmdDef> toplevel_cmddef_;
170 boost::scoped_ptr<Server> lyx_server_;
172 boost::scoped_ptr<ServerSocket> lyx_socket_;
174 boost::scoped_ptr<frontend::Application> application_;
175 /// lyx session, containing lastfiles, lastfilepos, and lastopened
176 boost::scoped_ptr<Session> session_;
178 /// Files to load at start.
179 vector<FileName> files_to_load_;
181 /// The messages translators.
182 map<string, Messages> messages_;
184 /// The file converters.
185 Converters converters_;
187 // The system converters copy after reading lyxrc.defaults.
188 Converters system_converters_;
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);
234 BufferList & LyX::bufferList()
236 return pimpl_->buffer_list_;
240 BufferList const & LyX::bufferList() const
242 return pimpl_->buffer_list_;
246 Session & LyX::session()
248 BOOST_ASSERT(pimpl_->session_.get());
249 return *pimpl_->session_.get();
253 Session const & LyX::session() const
255 BOOST_ASSERT(pimpl_->session_.get());
256 return *pimpl_->session_.get();
260 LyXFunc & LyX::lyxFunc()
262 return pimpl_->lyxfunc_;
266 LyXFunc const & LyX::lyxFunc() const
268 return pimpl_->lyxfunc_;
272 Server & LyX::server()
274 BOOST_ASSERT(pimpl_->lyx_server_.get());
275 return *pimpl_->lyx_server_.get();
279 Server const & LyX::server() const
281 BOOST_ASSERT(pimpl_->lyx_server_.get());
282 return *pimpl_->lyx_server_.get();
286 ServerSocket & LyX::socket()
288 BOOST_ASSERT(pimpl_->lyx_socket_.get());
289 return *pimpl_->lyx_socket_.get();
293 ServerSocket const & LyX::socket() const
295 BOOST_ASSERT(pimpl_->lyx_socket_.get());
296 return *pimpl_->lyx_socket_.get();
300 frontend::Application & LyX::application()
302 BOOST_ASSERT(pimpl_->application_.get());
303 return *pimpl_->application_.get();
307 frontend::Application const & LyX::application() const
309 BOOST_ASSERT(pimpl_->application_.get());
310 return *pimpl_->application_.get();
314 KeyMap & LyX::topLevelKeymap()
316 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
317 return *pimpl_->toplevel_keymap_.get();
321 CmdDef & LyX::topLevelCmdDef()
323 BOOST_ASSERT(pimpl_->toplevel_cmddef_.get());
324 return *pimpl_->toplevel_cmddef_.get();
328 Converters & LyX::converters()
330 return pimpl_->converters_;
334 Converters & LyX::systemConverters()
336 return pimpl_->system_converters_;
340 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 * LyX::updateInset(Inset const * inset) const
376 if (quitting || !inset)
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 void LyX::hideDialogs(std::string const & name, Inset * inset) const
395 if (quitting || !use_gui)
398 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
399 vector<int>::const_iterator it = view_ids.begin();
400 vector<int>::const_iterator const end = view_ids.end();
401 for (; it != end; ++it)
402 pimpl_->application_->gui().view(*it).getDialogs().
407 int LyX::exec(int & argc, char * argv[])
409 // Here we need to parse the command line. At least
410 // we need to parse for "-dbg" and "-help"
411 easyParse(argc, argv);
414 support::init_package(to_utf8(from_local8bit(argv[0])),
415 cl_system_support, cl_user_support,
416 support::top_build_dir_is_one_level_up);
417 } catch (support::ExceptionMessage const & message) {
418 if (message.type_ == support::ErrorException) {
419 Alert::error(message.title_, message.details_);
421 } else if (message.type_ == support::WarningException) {
422 Alert::warning(message.title_, message.details_);
426 // Reinit the messages machinery in case package() knows
427 // something interesting about the locale directory.
431 // FIXME: create a ConsoleApplication
432 int exit_status = init(argc, argv);
440 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
445 BufferList::iterator begin = pimpl_->buffer_list_.begin();
447 bool final_success = false;
448 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
450 if (buf != buf->masterBuffer())
452 bool success = false;
453 buf->dispatch(batch_command, &success);
454 final_success |= success;
457 return !final_success;
460 // Let the frontend parse and remove all arguments that it knows
461 pimpl_->application_.reset(createApplication(argc, argv));
465 // Parse and remove all known arguments in the LyX singleton
466 // Give an error for all remaining ones.
467 int exit_status = init(argc, argv);
469 // Kill the application object before exiting.
470 pimpl_->application_.reset();
477 /* Create a CoreApplication class that will provide the main event loop
478 * and the socket callback registering. With Qt4, only QtCore
479 * library would be needed.
480 * When this is done, a server_mode could be created and the following two
481 * line would be moved out from here.
483 // Note: socket callback must be registered after init(argc, argv)
484 // such that package().temp_dir() is properly initialized.
485 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
486 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
487 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
489 // Start the real execution loop.
490 exit_status = pimpl_->application_->exec();
498 void LyX::prepareExit()
500 // Clear the clipboard and selection stack:
501 cap::clearCutStack();
502 cap::clearSelection();
504 // Set a flag that we do quitting from the program,
505 // so no refreshes are necessary.
508 // close buffers first
509 pimpl_->buffer_list_.closeAll();
511 // do any other cleanup procedures now
512 if (package().temp_dir() != package().system_temp_dir()) {
513 LYXERR(Debug::INFO) << "Deleting tmp dir "
514 << package().temp_dir().absFilename() << endl;
516 if (!package().temp_dir().destroyDirectory()) {
517 docstring const msg =
518 bformat(_("Unable to remove the temporary directory %1$s"),
519 from_utf8(package().temp_dir().absFilename()));
520 Alert::warning(_("Unable to remove temporary directory"), msg);
525 if (pimpl_->session_)
526 pimpl_->session_->writeFile();
527 pimpl_->session_.reset();
528 pimpl_->lyx_server_.reset();
529 pimpl_->lyx_socket_.reset();
532 // Kill the application object before exiting. This avoids crashes
533 // when exiting on Linux.
534 if (pimpl_->application_)
535 pimpl_->application_.reset();
539 void LyX::earlyExit(int status)
541 BOOST_ASSERT(pimpl_->application_.get());
542 // LyX::pimpl_::application_ is not initialised at this
543 // point so it's safe to just exit after some cleanup.
549 int LyX::init(int & argc, char * argv[])
551 // check for any spurious extra arguments
552 // other than documents
553 for (int argi = 1; argi < argc ; ++argi) {
554 if (argv[argi][0] == '-') {
556 bformat(_("Wrong command line option `%1$s'. Exiting."),
557 from_utf8(argv[argi]))) << endl;
562 // Initialization of LyX (reads lyxrc and more)
563 LYXERR(Debug::INIT) << "Initializing LyX::init..." << endl;
564 bool success = init();
565 LYXERR(Debug::INIT) << "Initializing LyX::init...done" << endl;
569 for (int argi = argc - 1; argi >= 1; --argi) {
570 // get absolute path of file and add ".lyx" to
571 // the filename if necessary
572 pimpl_->files_to_load_.push_back(fileSearch(string(),
573 os::internal_path(to_utf8(from_local8bit(argv[argi]))),
574 "lyx", support::allow_unreadable));
578 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
584 void LyX::addFileToLoad(FileName const & fname)
586 vector<FileName>::const_iterator cit = std::find(
587 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
590 if (cit == pimpl_->files_to_load_.end())
591 pimpl_->files_to_load_.push_back(fname);
595 void LyX::loadFiles()
597 vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
598 vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
600 for (; it != end; ++it) {
604 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
605 if (buf->loadLyXFile(*it)) {
606 ErrorList const & el = buf->errorList("Parse");
608 for_each(el.begin(), el.end(),
609 boost::bind(&LyX::printError, this, _1));
612 pimpl_->buffer_list_.release(buf);
617 void LyX::execBatchCommands()
619 // The advantage of doing this here is that the event loop
620 // is already started. So any need for interaction will be
624 // if reconfiguration is needed.
625 if (textclasslist.empty()) {
626 switch (Alert::prompt(
627 _("No textclass is found"),
628 _("LyX cannot continue because no textclass is found. "
629 "You can either reconfigure normally, or reconfigure using "
630 "default textclasses, or quit LyX."),
637 // regular reconfigure
638 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
641 // reconfigure --without-latex-config
642 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
643 " --without-latex-config"));
646 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
650 // Execute batch commands if available
651 if (batch_command.empty())
654 LYXERR(Debug::INIT) << "About to handle -x '"
655 << batch_command << '\'' << endl;
657 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
661 void LyX::restoreGuiSession()
663 LyXView * view = newLyXView();
665 // if there is no valid class list, do not load any file.
666 if (textclasslist.empty())
669 // if some files were specified at command-line we assume that the
670 // user wants to edit *these* files and not to restore the session.
671 if (!pimpl_->files_to_load_.empty()) {
672 for_each(pimpl_->files_to_load_.begin(),
673 pimpl_->files_to_load_.end(),
674 bind(&LyXView::loadLyXFile, view, _1, true));
675 // clear this list to save a few bytes of RAM
676 pimpl_->files_to_load_.clear();
677 pimpl_->session_->lastOpened().clear();
679 } else if (lyxrc.load_session) {
680 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
681 // do not add to the lastfile list since these files are restored from
682 // last session, and should be already there (regular files), or should
683 // not be added at all (help files).
684 for_each(lastopened.begin(), lastopened.end(),
685 bind(&LyXView::loadLyXFile, view, _1, false));
687 // clear this list to save a few bytes of RAM
688 pimpl_->session_->lastOpened().clear();
691 BufferList::iterator I = pimpl_->buffer_list_.begin();
692 BufferList::iterator end = pimpl_->buffer_list_.end();
693 for (; I != end; ++I) {
695 if (buf != buf->masterBuffer())
700 // FIXME: Switch to the last loaded Buffer. This must not be the first one
701 // because the Buffer won't be connected in this case. The correct solution
702 // would be to avoid the manual connection of the current Buffer in LyXView.
703 if (!pimpl_->buffer_list_.empty())
704 view->setBuffer(pimpl_->buffer_list_.last());
708 LyXView * LyX::newLyXView()
713 // determine windows size and position, from lyxrc and/or session
715 unsigned int width = 690;
716 unsigned int height = 510;
717 // default icon size, will be overwritten by stored session value
718 unsigned int iconSizeXY = 0;
719 int maximized = LyXView::NotMaximized;
721 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
722 width = lyxrc.geometry_width;
723 height = lyxrc.geometry_height;
725 // if lyxrc returns (0,0), then use session info
727 string val = session().sessionInfo().load("WindowWidth");
729 width = convert<unsigned int>(val);
730 val = session().sessionInfo().load("WindowHeight");
732 height = convert<unsigned int>(val);
733 val = session().sessionInfo().load("WindowMaximized");
735 maximized = convert<int>(val);
736 val = session().sessionInfo().load("IconSizeXY");
738 iconSizeXY = convert<unsigned int>(val);
741 // if user wants to restore window position
744 if (lyxrc.geometry_xysaved) {
745 string val = session().sessionInfo().load("WindowPosX");
747 posx = convert<int>(val);
748 val = session().sessionInfo().load("WindowPosY");
750 posy = convert<int>(val);
753 if (!geometryArg.empty())
759 // create the main window
760 LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximized, iconSizeXY, geometryArg);
768 The SIGHUP signal does not exist on Windows and does not need to be handled.
770 Windows handles SIGFPE and SIGSEGV signals as expected.
772 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
773 cause a new thread to be spawned. This may well result in unexpected
774 behaviour by the single-threaded LyX.
776 SIGTERM signals will come only from another process actually sending
777 that signal using 'raise' in Windows' POSIX compatability layer. It will
778 not come from the general "terminate process" methods that everyone
779 actually uses (and which can't be trapped). Killing an app 'politely' on
780 Windows involves first sending a WM_CLOSE message, something that is
781 caught already by the Qt frontend.
783 For more information see:
785 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
786 ...signals are mostly useless on Windows for a variety of reasons that are
789 'UNIX Application Migration Guide, Chapter 9'
790 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
792 'How To Terminate an Application "Cleanly" in Win32'
793 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
797 static void error_handler(int err_sig)
799 // Throw away any signals other than the first one received.
800 static sig_atomic_t handling_error = false;
803 handling_error = true;
805 // We have received a signal indicating a fatal error, so
806 // try and save the data ASAP.
807 LyX::cref().emergencyCleanup();
809 // These lyxerr calls may or may not work:
811 // Signals are asynchronous, so the main program may be in a very
812 // fragile state when a signal is processed and thus while a signal
813 // handler function executes.
814 // In general, therefore, we should avoid performing any
815 // I/O operations or calling most library and system functions from
818 // This shouldn't matter here, however, as we've already invoked
823 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
827 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
830 lyxerr << "\nlyx: SIGSEGV signal caught\n"
831 "Sorry, you have found a bug in LyX. "
832 "Please read the bug-reporting instructions "
833 "in Help->Introduction and send us a bug report, "
834 "if necessary. Thanks !\nBye." << endl;
842 // Deinstall the signal handlers
844 signal(SIGHUP, SIG_DFL);
846 signal(SIGINT, SIG_DFL);
847 signal(SIGFPE, SIG_DFL);
848 signal(SIGSEGV, SIG_DFL);
849 signal(SIGTERM, SIG_DFL);
852 if (err_sig == SIGSEGV ||
853 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
855 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
864 void LyX::printError(ErrorItem const & ei)
866 docstring tmp = _("LyX: ") + ei.error + char_type(':')
868 std::cerr << to_utf8(tmp) << std::endl;
872 void LyX::initGuiFont()
874 if (lyxrc.roman_font_name.empty())
875 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
877 if (lyxrc.sans_font_name.empty())
878 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
880 if (lyxrc.typewriter_font_name.empty())
881 lyxrc.typewriter_font_name
882 = pimpl_->application_->typewriterFontName();
889 signal(SIGHUP, error_handler);
891 signal(SIGFPE, error_handler);
892 signal(SIGSEGV, error_handler);
893 signal(SIGINT, error_handler);
894 signal(SIGTERM, error_handler);
895 // SIGPIPE can be safely ignored.
897 lyxrc.tempdir_path = package().temp_dir().absFilename();
898 lyxrc.document_path = package().document_dir().absFilename();
900 if (lyxrc.template_path.empty()) {
901 lyxrc.template_path = addPath(package().system_support().absFilename(),
906 // Read configuration files
909 // This one may have been distributed along with LyX.
910 if (!readRcFile("lyxrc.dist"))
913 // Set the language defined by the distributor.
914 //setGuiLanguage(lyxrc.gui_language);
916 // Set the PATH correctly.
917 #if !defined (USE_POSIX_PACKAGING)
918 // Add the directory containing the LyX executable to the path
919 // so that LyX can find things like tex2lyx.
920 if (package().build_support().empty())
921 prependEnvPath("PATH", package().binary_dir().absFilename());
923 if (!lyxrc.path_prefix.empty())
924 prependEnvPath("PATH", lyxrc.path_prefix);
926 // Check that user LyX directory is ok.
927 if (queryUserLyXDir(package().explicit_user_support()))
928 reconfigureUserLyXDir();
930 // no need for a splash when there is no GUI
935 // This one is generated in user_support directory by lib/configure.py.
936 if (!readRcFile("lyxrc.defaults"))
939 // Query the OS to know what formats are viewed natively
940 formats.setAutoOpen();
942 // Read lyxrc.dist again to be able to override viewer auto-detection.
943 readRcFile("lyxrc.dist");
945 system_lyxrc = lyxrc;
946 system_formats = formats;
947 pimpl_->system_converters_ = pimpl_->converters_;
948 pimpl_->system_movers_ = pimpl_->movers_;
949 system_lcolor = lcolor;
951 // This one is edited through the preferences dialog.
952 if (!readRcFile("preferences"))
955 if (!readEncodingsFile("encodings", "unicodesymbols"))
957 if (!readLanguagesFile("languages"))
961 LYXERR(Debug::INIT) << "Reading layouts..." << endl;
967 // read keymap and ui files in batch mode as well
968 // because InsetInfo needs to know these to produce
969 // the correct output
971 // Set the language defined by the user.
972 //setGuiLanguage(lyxrc.gui_language);
974 // Set up command definitions
975 pimpl_->toplevel_cmddef_.reset(new CmdDef);
976 pimpl_->toplevel_cmddef_->read(lyxrc.def_file);
979 pimpl_->toplevel_keymap_.reset(new KeyMap);
980 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
981 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
982 // load user bind file user.bind
983 pimpl_->toplevel_keymap_->read("user");
985 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
988 if (!readUIFile(lyxrc.ui_file))
991 if (lyxerr.debugging(Debug::LYXRC))
994 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
995 if (!lyxrc.path_prefix.empty())
996 prependEnvPath("PATH", lyxrc.path_prefix);
998 FileName const document_path(lyxrc.document_path);
999 if (document_path.exists() && document_path.isDirectory())
1000 package().document_dir() = document_path;
1002 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
1003 if (package().temp_dir().empty()) {
1004 Alert::error(_("Could not create temporary directory"),
1005 bformat(_("Could not create a temporary directory in\n"
1006 "%1$s. Make sure that this\n"
1007 "path exists and is writable and try again."),
1008 from_utf8(lyxrc.tempdir_path)));
1009 // createLyXTmpDir() tries sufficiently hard to create a
1010 // usable temp dir, so the probability to come here is
1011 // close to zero. We therefore don't try to overcome this
1012 // problem with e.g. asking the user for a new path and
1013 // trying again but simply exit.
1017 LYXERR(Debug::INIT) << "LyX tmp dir: `"
1018 << package().temp_dir().absFilename()
1021 LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
1022 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
1024 // This must happen after package initialization and after lyxrc is
1025 // read, therefore it can't be done by a static object.
1026 ConverterCache::init();
1032 void LyX::defaultKeyBindings(KeyMap * kbmap)
1034 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
1035 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
1036 kbmap->bind("Up", FuncRequest(LFUN_UP));
1037 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
1039 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
1040 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
1041 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
1042 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
1044 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
1045 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
1046 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
1047 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
1049 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
1050 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
1052 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
1053 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
1055 // kbmap->bindings to enable the use of the numeric keypad
1056 // e.g. Num Lock set
1057 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
1058 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
1059 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
1060 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
1061 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
1062 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
1063 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
1064 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
1065 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
1066 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
1067 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
1068 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
1069 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
1070 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
1071 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
1072 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
1073 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
1074 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
1075 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
1076 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
1077 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
1078 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
1079 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
1080 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
1084 void LyX::emergencyCleanup() const
1086 // what to do about tmpfiles is non-obvious. we would
1087 // like to delete any we find, but our lyxdir might
1088 // contain documents etc. which might be helpful on
1091 pimpl_->buffer_list_.emergencyWriteAll();
1093 if (pimpl_->lyx_server_)
1094 pimpl_->lyx_server_->emergencyCleanup();
1095 pimpl_->lyx_server_.reset();
1096 pimpl_->lyx_socket_.reset();
1101 void LyX::deadKeyBindings(KeyMap * kbmap)
1103 // bindKeyings for transparent handling of deadkeys
1104 // The keysyms are gotten from XFree86 X11R6
1105 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1106 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1107 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1108 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1109 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1110 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1111 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1112 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1113 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1114 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1115 // nothing with this name
1116 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1117 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1118 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1119 // nothing with this name either...
1120 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1121 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1122 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1123 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1127 // return true if file does not exist or is older than configure.py.
1128 static bool needsUpdate(string const & file)
1130 // We cannot initialize configure_script directly because the package
1131 // is not initialized yet when static objects are constructed.
1132 static FileName configure_script;
1133 static bool firstrun = true;
1136 FileName(addName(package().system_support().absFilename(),
1142 FileName(addName(package().user_support().absFilename(), file));
1143 return !absfile.exists()
1144 || configure_script.lastModified() > absfile.lastModified();
1148 bool LyX::queryUserLyXDir(bool explicit_userdir)
1150 // Does user directory exist?
1151 FileName const sup = package().user_support();
1152 if (sup.exists() && sup.isDirectory()) {
1153 first_start = false;
1155 return needsUpdate("lyxrc.defaults")
1156 || needsUpdate("lyxmodules.lst")
1157 || needsUpdate("textclass.lst")
1158 || needsUpdate("packages.lst");
1161 first_start = !explicit_userdir;
1163 // If the user specified explicitly a directory, ask whether
1164 // to create it. If the user says "no", then exit.
1165 if (explicit_userdir &&
1167 _("Missing user LyX directory"),
1168 bformat(_("You have specified a non-existent user "
1169 "LyX directory, %1$s.\n"
1170 "It is needed to keep your own configuration."),
1171 from_utf8(package().user_support().absFilename())),
1173 _("&Create directory"),
1175 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1176 earlyExit(EXIT_FAILURE);
1179 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1180 from_utf8(sup.absFilename()))) << endl;
1182 if (!sup.createDirectory(0755)) {
1183 // Failed, so let's exit.
1184 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1186 earlyExit(EXIT_FAILURE);
1193 bool LyX::readRcFile(string const & name)
1195 LYXERR(Debug::INIT) << "About to read " << name << "... ";
1197 FileName const lyxrc_path = libFileSearch(string(), name);
1198 if (!lyxrc_path.empty()) {
1200 LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
1202 if (lyxrc.read(lyxrc_path) < 0) {
1203 showFileError(name);
1207 LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
1213 // Read the ui file `name'
1214 bool LyX::readUIFile(string const & name, bool include)
1224 struct keyword_item uitags[ui_last - 1] = {
1225 { "include", ui_include },
1226 { "menuset", ui_menuset },
1227 { "toolbars", ui_toolbars },
1228 { "toolbarset", ui_toolbarset }
1231 // Ensure that a file is read only once (prevents include loops)
1232 static std::list<string> uifiles;
1233 std::list<string>::const_iterator it = uifiles.begin();
1234 std::list<string>::const_iterator end = uifiles.end();
1235 it = std::find(it, end, name);
1237 LYXERR(Debug::INIT) << "UI file '" << name
1238 << "' has been read already. "
1239 << "Is this an include loop?"
1244 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1249 ui_path = libFileSearch("ui", name, "inc");
1250 if (ui_path.empty())
1251 ui_path = libFileSearch("ui",
1252 changeExtension(name, "inc"));
1255 ui_path = libFileSearch("ui", name, "ui");
1257 if (ui_path.empty()) {
1258 LYXERR(Debug::INIT) << "Could not find " << name << endl;
1259 showFileError(name);
1263 uifiles.push_back(name);
1265 LYXERR(Debug::INIT) << "Found " << name
1266 << " in " << ui_path << endl;
1267 Lexer lex(uitags, ui_last - 1);
1268 lex.setFile(ui_path);
1270 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1274 if (lyxerr.debugging(Debug::PARSER))
1275 lex.printTable(lyxerr);
1277 while (lex.isOK()) {
1278 switch (lex.lex()) {
1281 string const file = lex.getString();
1282 if (!readUIFile(file, true))
1287 menubackend.read(lex);
1291 toolbarbackend.readToolbars(lex);
1295 toolbarbackend.readToolbarSettings(lex);
1299 if (!rtrim(lex.getString()).empty())
1300 lex.printError("LyX::ReadUIFile: "
1301 "Unknown menu tag: `$$Token'");
1309 // Read the languages file `name'
1310 bool LyX::readLanguagesFile(string const & name)
1312 LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1314 FileName const lang_path = libFileSearch(string(), name);
1315 if (lang_path.empty()) {
1316 showFileError(name);
1319 languages.read(lang_path);
1324 // Read the encodings file `name'
1325 bool LyX::readEncodingsFile(string const & enc_name,
1326 string const & symbols_name)
1328 LYXERR(Debug::INIT) << "About to read " << enc_name << " and "
1329 << symbols_name << "..." << endl;
1331 FileName const symbols_path = libFileSearch(string(), symbols_name);
1332 if (symbols_path.empty()) {
1333 showFileError(symbols_name);
1337 FileName const enc_path = libFileSearch(string(), enc_name);
1338 if (enc_path.empty()) {
1339 showFileError(enc_name);
1342 encodings.read(enc_path, symbols_path);
1351 /// return the the number of arguments consumed
1352 typedef boost::function<int(string const &, string const &)> cmd_helper;
1354 int parse_dbg(string const & arg, string const &)
1357 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1358 Debug::showTags(lyxerr);
1361 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1363 lyxerr.level(Debug::value(arg));
1364 Debug::showLevel(lyxerr, lyxerr.level());
1369 int parse_help(string const &, string const &)
1372 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1373 "Command line switches (case sensitive):\n"
1374 "\t-help summarize LyX usage\n"
1375 "\t-userdir dir set user directory to dir\n"
1376 "\t-sysdir dir set system directory to dir\n"
1377 "\t-geometry WxH+X+Y set geometry of the main window\n"
1378 "\t-dbg feature[,feature]...\n"
1379 " select the features to debug.\n"
1380 " Type `lyx -dbg' to see the list of features\n"
1381 "\t-x [--execute] command\n"
1382 " where command is a lyx command.\n"
1383 "\t-e [--export] fmt\n"
1384 " where fmt is the export format of choice.\n"
1385 "\t-i [--import] fmt file.xxx\n"
1386 " where fmt is the import format of choice\n"
1387 " and file.xxx is the file to be imported.\n"
1388 "\t-version summarize version and build info\n"
1389 "Check the LyX man page for more details.")) << endl;
1394 int parse_version(string const &, string const &)
1396 lyxerr << "LyX " << lyx_version
1397 << " (" << lyx_release_date << ")" << endl;
1398 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1400 lyxerr << lyx_version_info << endl;
1405 int parse_sysdir(string const & arg, string const &)
1408 Alert::error(_("No system directory"),
1409 _("Missing directory for -sysdir switch"));
1412 cl_system_support = arg;
1416 int parse_userdir(string const & arg, string const &)
1419 Alert::error(_("No user directory"),
1420 _("Missing directory for -userdir switch"));
1423 cl_user_support = arg;
1427 int parse_execute(string const & arg, string const &)
1430 Alert::error(_("Incomplete command"),
1431 _("Missing command string after --execute switch"));
1438 int parse_export(string const & type, string const &)
1441 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1442 "--export switch")) << endl;
1445 batch = "buffer-export " + type;
1450 int parse_import(string const & type, string const & file)
1453 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1454 "--import switch")) << endl;
1458 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1462 batch = "buffer-import " + type + ' ' + file;
1466 int parse_geometry(string const & arg1, string const &)
1469 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1470 // remove also the arg
1473 // don't remove "-geometry"
1482 void LyX::easyParse(int & argc, char * argv[])
1484 std::map<string, cmd_helper> cmdmap;
1486 cmdmap["-dbg"] = parse_dbg;
1487 cmdmap["-help"] = parse_help;
1488 cmdmap["--help"] = parse_help;
1489 cmdmap["-version"] = parse_version;
1490 cmdmap["--version"] = parse_version;
1491 cmdmap["-sysdir"] = parse_sysdir;
1492 cmdmap["-userdir"] = parse_userdir;
1493 cmdmap["-x"] = parse_execute;
1494 cmdmap["--execute"] = parse_execute;
1495 cmdmap["-e"] = parse_export;
1496 cmdmap["--export"] = parse_export;
1497 cmdmap["-i"] = parse_import;
1498 cmdmap["--import"] = parse_import;
1499 cmdmap["-geometry"] = parse_geometry;
1501 for (int i = 1; i < argc; ++i) {
1502 std::map<string, cmd_helper>::const_iterator it
1503 = cmdmap.find(argv[i]);
1505 // don't complain if not found - may be parsed later
1506 if (it == cmdmap.end())
1509 string const arg((i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string());
1510 string const arg2((i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string());
1512 int const remove = 1 + it->second(arg, arg2);
1514 // Now, remove used arguments by shifting
1515 // the following ones remove places down.
1518 for (int j = i; j < argc; ++j)
1519 argv[j] = argv[j + remove];
1524 batch_command = batch;
1528 FuncStatus getStatus(FuncRequest const & action)
1530 return LyX::ref().lyxFunc().getStatus(action);
1534 void dispatch(FuncRequest const & action)
1536 LyX::ref().lyxFunc().dispatch(action);
1540 BufferList & theBufferList()
1542 return LyX::ref().bufferList();
1546 LyXFunc & theLyXFunc()
1548 return LyX::ref().lyxFunc();
1552 Server & theServer()
1554 // FIXME: this should not be use_gui dependent
1555 BOOST_ASSERT(use_gui);
1556 return LyX::ref().server();
1560 ServerSocket & theServerSocket()
1562 // FIXME: this should not be use_gui dependent
1563 BOOST_ASSERT(use_gui);
1564 return LyX::ref().socket();
1568 KeyMap & theTopLevelKeymap()
1570 return LyX::ref().topLevelKeymap();
1574 Converters & theConverters()
1576 return LyX::ref().converters();
1580 Converters & theSystemConverters()
1582 return LyX::ref().systemConverters();
1586 Movers & theMovers()
1588 return LyX::ref().pimpl_->movers_;
1592 Mover const & getMover(std::string const & fmt)
1594 return LyX::ref().pimpl_->movers_(fmt);
1598 void setMover(std::string const & fmt, std::string const & command)
1600 LyX::ref().pimpl_->movers_.set(fmt, command);
1604 Movers & theSystemMovers()
1606 return LyX::ref().pimpl_->system_movers_;
1610 Messages & getMessages(std::string const & language)
1612 return LyX::ref().getMessages(language);
1616 Messages & getGuiMessages()
1618 return LyX::ref().getGuiMessages();