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"
44 #include "ToolbarBackend.h"
46 #include "frontends/Alert.h"
47 #include "frontends/Application.h"
48 #include "frontends/Gui.h"
49 #include "frontends/LyXView.h"
51 #include "support/environment.h"
52 #include "support/filetools.h"
53 #include "support/fontutils.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"
61 #include <boost/bind.hpp>
62 #include <boost/filesystem/operations.hpp>
70 using support::addName;
71 using support::addPath;
72 using support::bformat;
73 using support::createDirectory;
74 using support::createLyXTmpDir;
75 using support::destroyDir;
76 using support::fileSearch;
77 using support::getEnv;
78 using support::i18nLibFileSearch;
79 using support::libFileSearch;
80 using support::package;
81 using support::prependEnvPath;
83 using support::Systemcall;
85 namespace Alert = frontend::Alert;
86 namespace os = support::os;
87 namespace fs = boost::filesystem;
94 #ifndef CXX_GLOBAL_CSTD
101 frontend::Application * theApp = 0;
103 /// are we using the GUI at all?
105 * We default to true and this is changed to false when the export feature is used.
112 // Filled with the command line arguments "foo" of "-sysdir foo" or
114 string cl_system_support;
115 string cl_user_support;
118 void showFileError(string const & error)
120 Alert::warning(_("Could not read configuration file"),
121 bformat(_("Error while reading the configuration file\n%1$s.\n"
122 "Please check your installation."), from_utf8(error)));
126 void reconfigureUserLyXDir()
128 string const configure_command = package().configure_command();
130 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
131 support::Path p(package().user_support());
133 one.startscript(Systemcall::Wait, configure_command);
134 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
140 /// The main application class private implementation.
141 struct LyX::Singletons
143 /// our function handler
146 BufferList buffer_list_;
148 boost::scoped_ptr<kb_keymap> toplevel_keymap_;
150 boost::scoped_ptr<LyXServer> lyx_server_;
152 boost::scoped_ptr<LyXServerSocket> lyx_socket_;
154 boost::scoped_ptr<frontend::Application> application_;
155 /// lyx session, containing lastfiles, lastfilepos, and lastopened
156 boost::scoped_ptr<Session> session_;
160 boost::scoped_ptr<LyX> LyX::singleton_;
164 // Static data are not treated in the same way at all on the Mac (and
165 // the LyX singleton has static methods). This is the reason why the
166 // exit command on the Mac bypasses our dispatch machinery altogether.
167 // On Linux and Windows we won't pass a second time through quit()
168 // because quitting will already be set to true.
174 int LyX::exec(int & argc, char * argv[])
176 BOOST_ASSERT(!singleton_.get());
177 // We must return from this before launching the gui so that
178 // other parts of the code can access singleton_ through
179 // LyX::ref and LyX::cref.
180 singleton_.reset(new LyX);
181 // Start the real execution loop.
182 return singleton_->priv_exec(argc, argv);
188 BOOST_ASSERT(singleton_.get());
189 return *singleton_.get();
193 LyX const & LyX::cref()
195 BOOST_ASSERT(singleton_.get());
196 return *singleton_.get();
201 : first_start(false), geometryOption_(false)
203 pimpl_.reset(new Singletons);
207 BufferList & LyX::bufferList()
209 return pimpl_->buffer_list_;
213 BufferList const & LyX::bufferList() const
215 return pimpl_->buffer_list_;
219 Session & LyX::session()
221 BOOST_ASSERT(pimpl_->session_.get());
222 return *pimpl_->session_.get();
226 Session const & LyX::session() const
228 BOOST_ASSERT(pimpl_->session_.get());
229 return *pimpl_->session_.get();
233 LyXFunc & LyX::lyxFunc()
235 return pimpl_->lyxfunc_;
239 LyXFunc const & LyX::lyxFunc() const
241 return pimpl_->lyxfunc_;
245 LyXServer & LyX::server()
247 BOOST_ASSERT(pimpl_->lyx_server_.get());
248 return *pimpl_->lyx_server_.get();
252 LyXServer const & LyX::server() const
254 BOOST_ASSERT(pimpl_->lyx_server_.get());
255 return *pimpl_->lyx_server_.get();
259 LyXServerSocket & LyX::socket()
261 BOOST_ASSERT(pimpl_->lyx_socket_.get());
262 return *pimpl_->lyx_socket_.get();
266 LyXServerSocket const & LyX::socket() const
268 BOOST_ASSERT(pimpl_->lyx_socket_.get());
269 return *pimpl_->lyx_socket_.get();
273 frontend::Application & LyX::application()
275 BOOST_ASSERT(pimpl_->application_.get());
276 return *pimpl_->application_.get();
280 frontend::Application const & LyX::application() const
282 BOOST_ASSERT(pimpl_->application_.get());
283 return *pimpl_->application_.get();
287 kb_keymap & LyX::topLevelKeymap()
289 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
290 return *pimpl_->toplevel_keymap_.get();
294 kb_keymap const & LyX::topLevelKeymap() const
296 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
297 return *pimpl_->toplevel_keymap_.get();
301 Buffer const * const LyX::updateInset(InsetBase const * inset) const
306 Buffer const * buffer_ptr = 0;
307 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
308 vector<int>::const_iterator it = view_ids.begin();
309 vector<int>::const_iterator const end = view_ids.end();
310 for (; it != end; ++it) {
312 pimpl_->application_->gui().view(*it).updateInset(inset);
320 int LyX::priv_exec(int & argc, char * argv[])
322 // Here we need to parse the command line. At least
323 // we need to parse for "-dbg" and "-help"
324 easyParse(argc, argv);
326 support::init_package(argv[0], cl_system_support, cl_user_support,
327 support::top_build_dir_is_one_level_up);
329 vector<string> files;
330 int exit_status = execBatchCommands(argc, argv, files);
336 // Force adding of font path _before_ Application is initialized
337 support::addFontResources();
338 pimpl_->application_.reset(createApplication(argc, argv));
340 // FIXME: this global pointer should probably go.
341 theApp = pimpl_->application_.get();
342 restoreGuiSession(files);
343 // Start the real execution loop.
346 /* Create a CoreApplication class that will provide the main event loop
347 * and the socket callback registering. With Qt4, only QtCore
348 * library would be needed.
349 * When this is done, a server_mode could be created and the following two
350 * line would be moved out from here.
352 pimpl_->lyx_server_.reset(new LyXServer(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
353 pimpl_->lyx_socket_.reset(new LyXServerSocket(&pimpl_->lyxfunc_,
354 support::os::internal_path(package().temp_dir() + "/lyxsocket")));
356 // handle the batch commands the user asked for
357 if (!batch_command.empty()) {
358 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
361 exit_status = pimpl_->application_->start(batch_command);
362 // Kill the application object before exiting. This avoid crash
364 pimpl_->application_.reset();
365 // Restore original font resources after Application is destroyed.
366 support::restoreFontResources();
369 // FIXME: create a ConsoleApplication
377 void LyX::prepareExit()
379 // Set a flag that we do quitting from the program,
380 // so no refreshes are necessary.
383 // close buffers first
384 pimpl_->buffer_list_.closeAll();
386 // do any other cleanup procedures now
387 lyxerr[Debug::INFO] << "Deleting tmp dir " << package().temp_dir() << endl;
389 if (!destroyDir(package().temp_dir())) {
390 docstring const msg =
391 bformat(_("Unable to remove the temporary directory %1$s"),
392 from_utf8(package().temp_dir()));
393 Alert::warning(_("Unable to remove temporary directory"), msg);
398 void LyX::earlyExit(int status)
400 BOOST_ASSERT(pimpl_->application_.get());
401 // LyX::pimpl_::application_ is not initialised at this
402 // point so it's safe to just exit after some cleanup.
410 lyxerr[Debug::INFO] << "Running QuitLyX." << endl;
415 pimpl_->session_->writeFile();
416 pimpl_->lyx_server_.reset();
417 pimpl_->lyx_socket_.reset();
418 pimpl_->application_->exit(0);
423 int LyX::execBatchCommands(int & argc, char * argv[],
424 vector<string> & files)
426 // check for any spurious extra arguments
427 // other than documents
428 for (int argi = 1; argi < argc ; ++argi) {
429 if (argv[argi][0] == '-') {
431 bformat(_("Wrong command line option `%1$s'. Exiting."),
432 from_utf8(argv[argi]))) << endl;
437 // Initialization of LyX (reads lyxrc and more)
438 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
439 bool success = init();
440 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
444 for (int argi = argc - 1; argi >= 1; --argi)
445 files.push_back(os::internal_path(argv[argi]));
448 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
450 // Execute batch commands if available
451 if (!batch_command.empty()) {
453 lyxerr[Debug::INIT] << "About to handle -x '"
454 << batch_command << '\'' << endl;
456 Buffer * last_loaded = 0;
458 vector<string>::const_iterator it = files.begin();
459 vector<string>::const_iterator end = files.end();
461 for (; it != end; ++it) {
462 // get absolute path of file and add ".lyx" to
463 // the filename if necessary
464 string s = fileSearch(string(), *it, "lyx");
466 Buffer * const b = newFile(*it, string(), true);
470 Buffer * buf = pimpl_->buffer_list_.newBuffer(s, false);
471 if (loadLyXFile(buf, s)) {
473 ErrorList const & el = buf->errorList("Parse");
475 for_each(el.begin(), el.end(),
476 boost::bind(&LyX::printError, this, _1));
479 pimpl_->buffer_list_.release(buf);
483 // try to dispatch to last loaded buffer first
486 if (last_loaded->dispatch(batch_command, &success)) {
491 files.clear(); // the files are already loaded
498 void LyX::restoreGuiSession(vector<string> const & files)
500 LyXView * view = newLyXView();
503 for_each(files.begin(), files.end(),
504 bind(&LyXView::loadLyXFile, view, _1, true));
506 // if a file is specified, I assume that user wants to edit *that* file
507 if (files.empty() && lyxrc.load_session) {
508 vector<string> const & lastopened = pimpl_->session_->lastOpened().getfiles();
509 // do not add to the lastfile list since these files are restored from
510 // last seesion, and should be already there (regular files), or should
511 // not be added at all (help files).
512 for_each(lastopened.begin(), lastopened.end(),
513 bind(&LyXView::loadLyXFile, view, _1, false));
515 // clear this list to save a few bytes of RAM
516 pimpl_->session_->lastOpened().clear();
520 LyXView * LyX::newLyXView()
525 // determine windows size and position, from lyxrc and/or session
527 unsigned int width = 690;
528 unsigned int height = 510;
529 bool maximize = false;
531 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
532 width = lyxrc.geometry_width;
533 height = lyxrc.geometry_height;
535 // if lyxrc returns (0,0), then use session info
537 string val = session().sessionInfo().load("WindowWidth");
539 width = convert<unsigned int>(val);
540 val = session().sessionInfo().load("WindowHeight");
542 height = convert<unsigned int>(val);
543 if (session().sessionInfo().load("WindowIsMaximized") == "yes")
547 // if user wants to restore window position
550 if (lyxrc.geometry_xysaved) {
551 string val = session().sessionInfo().load("WindowPosX");
553 posx = convert<int>(val);
554 val = session().sessionInfo().load("WindowPosY");
556 posy = convert<int>(val);
559 if (geometryOption_) {
563 // create the main window
564 LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximize);
572 The SIGHUP signal does not exist on Windows and does not need to be handled.
574 Windows handles SIGFPE and SIGSEGV signals as expected.
576 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
577 cause a new thread to be spawned. This may well result in unexpected
578 behaviour by the single-threaded LyX.
580 SIGTERM signals will come only from another process actually sending
581 that signal using 'raise' in Windows' POSIX compatability layer. It will
582 not come from the general "terminate process" methods that everyone
583 actually uses (and which can't be trapped). Killing an app 'politely' on
584 Windows involves first sending a WM_CLOSE message, something that is
585 caught already by the Qt frontend.
587 For more information see:
589 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
590 ...signals are mostly useless on Windows for a variety of reasons that are
593 'UNIX Application Migration Guide, Chapter 9'
594 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
596 'How To Terminate an Application "Cleanly" in Win32'
597 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
601 static void error_handler(int err_sig)
603 // Throw away any signals other than the first one received.
604 static sig_atomic_t handling_error = false;
607 handling_error = true;
609 // We have received a signal indicating a fatal error, so
610 // try and save the data ASAP.
611 LyX::cref().emergencyCleanup();
613 // These lyxerr calls may or may not work:
615 // Signals are asynchronous, so the main program may be in a very
616 // fragile state when a signal is processed and thus while a signal
617 // handler function executes.
618 // In general, therefore, we should avoid performing any
619 // I/O operations or calling most library and system functions from
622 // This shouldn't matter here, however, as we've already invoked
627 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
631 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
634 lyxerr << "\nlyx: SIGSEGV signal caught\n"
635 "Sorry, you have found a bug in LyX. "
636 "Please read the bug-reporting instructions "
637 "in Help->Introduction and send us a bug report, "
638 "if necessary. Thanks !\nBye." << endl;
646 // Deinstall the signal handlers
648 signal(SIGHUP, SIG_DFL);
650 signal(SIGINT, SIG_DFL);
651 signal(SIGFPE, SIG_DFL);
652 signal(SIGSEGV, SIG_DFL);
653 signal(SIGTERM, SIG_DFL);
656 if (err_sig == SIGSEGV ||
657 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
659 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
668 void LyX::printError(ErrorItem const & ei)
670 docstring tmp = _("LyX: ") + ei.error + char_type(':')
672 std::cerr << to_utf8(tmp) << std::endl;
676 void LyX::initGuiFont()
678 if (lyxrc.roman_font_name.empty())
679 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
681 if (lyxrc.sans_font_name.empty())
682 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
684 if (lyxrc.typewriter_font_name.empty())
685 lyxrc.typewriter_font_name
686 = pimpl_->application_->typewriterFontName();
693 signal(SIGHUP, error_handler);
695 signal(SIGFPE, error_handler);
696 signal(SIGSEGV, error_handler);
697 signal(SIGINT, error_handler);
698 signal(SIGTERM, error_handler);
699 // SIGPIPE can be safely ignored.
701 lyxrc.tempdir_path = package().temp_dir();
702 lyxrc.document_path = package().document_dir();
704 if (lyxrc.template_path.empty()) {
705 lyxrc.template_path = addPath(package().system_support(),
710 // Read configuration files
713 // This one may have been distributed along with LyX.
714 if (!readRcFile("lyxrc.dist"))
717 // Set the PATH correctly.
718 #if !defined (USE_POSIX_PACKAGING)
719 // Add the directory containing the LyX executable to the path
720 // so that LyX can find things like tex2lyx.
721 if (package().build_support().empty())
722 prependEnvPath("PATH", package().binary_dir());
724 if (!lyxrc.path_prefix.empty())
725 prependEnvPath("PATH", lyxrc.path_prefix);
727 // Check that user LyX directory is ok.
728 if (queryUserLyXDir(package().explicit_user_support()))
729 reconfigureUserLyXDir();
731 // no need for a splash when there is no GUI
736 // This one is generated in user_support directory by lib/configure.py.
737 if (!readRcFile("lyxrc.defaults"))
740 // Query the OS to know what formats are viewed natively
741 formats.setAutoOpen();
743 // Read lyxrc.dist again to be able to override viewer auto-detection.
744 readRcFile("lyxrc.dist");
746 system_lyxrc = lyxrc;
747 system_formats = formats;
748 system_converters = converters;
749 system_movers = movers;
750 system_lcolor = lcolor;
752 // This one is edited through the preferences dialog.
753 if (!readRcFile("preferences"))
756 if (!readEncodingsFile("encodings"))
758 if (!readLanguagesFile("languages"))
762 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
768 pimpl_->toplevel_keymap_.reset(new kb_keymap);
769 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
770 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
772 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
775 if (!readUIFile(lyxrc.ui_file))
779 if (lyxerr.debugging(Debug::LYXRC))
782 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
783 if (!lyxrc.path_prefix.empty())
784 prependEnvPath("PATH", lyxrc.path_prefix);
786 if (fs::exists(lyxrc.document_path) &&
787 fs::is_directory(lyxrc.document_path))
788 package().document_dir() = lyxrc.document_path;
790 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
791 if (package().temp_dir().empty()) {
792 Alert::error(_("Could not create temporary directory"),
793 bformat(_("Could not create a temporary directory in\n"
794 "%1$s. Make sure that this\n"
795 "path exists and is writable and try again."),
796 from_utf8(lyxrc.tempdir_path)));
797 // createLyXTmpDir() tries sufficiently hard to create a
798 // usable temp dir, so the probability to come here is
799 // close to zero. We therefore don't try to overcome this
800 // problem with e.g. asking the user for a new path and
801 // trying again but simply exit.
805 if (lyxerr.debugging(Debug::INIT)) {
806 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
809 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
810 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
812 // This must happen after package initialization and after lyxrc is
813 // read, therefore it can't be done by a static object.
814 ConverterCache::init();
820 void LyX::defaultKeyBindings(kb_keymap * kbmap)
822 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
823 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
824 kbmap->bind("Up", FuncRequest(LFUN_UP));
825 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
827 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
828 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
829 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
830 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
832 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
833 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
834 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
835 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
837 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
838 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
840 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
841 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
843 // kbmap->bindings to enable the use of the numeric keypad
845 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
846 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
847 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
848 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
849 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
850 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
851 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
852 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
853 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
854 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
855 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
856 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
857 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
858 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
859 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
860 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
861 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
862 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
863 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
864 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
865 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
866 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
867 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
868 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
872 void LyX::emergencyCleanup() const
874 // what to do about tmpfiles is non-obvious. we would
875 // like to delete any we find, but our lyxdir might
876 // contain documents etc. which might be helpful on
879 pimpl_->buffer_list_.emergencyWriteAll();
881 pimpl_->lyx_server_->emergencyCleanup();
882 pimpl_->lyx_server_.reset();
883 pimpl_->lyx_socket_.reset();
888 void LyX::deadKeyBindings(kb_keymap * kbmap)
890 // bindKeyings for transparent handling of deadkeys
891 // The keysyms are gotten from XFree86 X11R6
892 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
893 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
894 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
895 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
896 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
897 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
898 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
899 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
900 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
901 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
902 // nothing with this name
903 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
904 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
905 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
906 // nothing with this name either...
907 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
908 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
909 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
910 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
916 // return true if file does not exist or is older than configure.py.
917 bool needsUpdate(string const & file)
919 static string const configure_script =
920 addName(package().system_support(), "configure.py");
921 string const absfile =
922 addName(package().user_support(), file);
924 return (! fs::exists(absfile))
925 || (fs::last_write_time(configure_script)
926 > fs::last_write_time(absfile));
932 bool LyX::queryUserLyXDir(bool explicit_userdir)
934 // Does user directory exist?
935 if (fs::exists(package().user_support()) &&
936 fs::is_directory(package().user_support())) {
939 return needsUpdate("lyxrc.defaults")
940 || needsUpdate("textclass.lst")
941 || needsUpdate("packages.lst");
944 first_start = !explicit_userdir;
946 // If the user specified explicitly a directory, ask whether
947 // to create it. If the user says "no", then exit.
948 if (explicit_userdir &&
950 _("Missing user LyX directory"),
951 bformat(_("You have specified a non-existent user "
952 "LyX directory, %1$s.\n"
953 "It is needed to keep your own configuration."),
954 from_utf8(package().user_support())),
956 _("&Create directory"),
958 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
959 earlyExit(EXIT_FAILURE);
962 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
963 from_utf8(package().user_support())))
966 if (!createDirectory(package().user_support(), 0755)) {
967 // Failed, so let's exit.
968 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
970 earlyExit(EXIT_FAILURE);
977 bool LyX::readRcFile(string const & name)
979 lyxerr[Debug::INIT] << "About to read " << name << "... ";
981 string const lyxrc_path = libFileSearch(string(), name);
982 if (!lyxrc_path.empty()) {
984 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
986 if (lyxrc.read(lyxrc_path) < 0) {
991 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
997 // Read the ui file `name'
998 bool LyX::readUIFile(string const & name)
1008 struct keyword_item uitags[ui_last - 1] = {
1009 { "include", ui_include },
1010 { "menuset", ui_menuset },
1011 { "toolbar", ui_toolbar },
1012 { "toolbars", ui_toolbars }
1015 // Ensure that a file is read only once (prevents include loops)
1016 static std::list<string> uifiles;
1017 std::list<string>::const_iterator it = uifiles.begin();
1018 std::list<string>::const_iterator end = uifiles.end();
1019 it = std::find(it, end, name);
1021 lyxerr[Debug::INIT] << "UI file '" << name
1022 << "' has been read already. "
1023 << "Is this an include loop?"
1028 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1030 string const ui_path = libFileSearch("ui", name, "ui");
1032 if (ui_path.empty()) {
1033 lyxerr[Debug::INIT] << "Could not find " << name << endl;
1034 showFileError(name);
1037 uifiles.push_back(name);
1039 lyxerr[Debug::INIT] << "Found " << name
1040 << " in " << ui_path << endl;
1041 LyXLex lex(uitags, ui_last - 1);
1042 lex.setFile(ui_path);
1044 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1048 if (lyxerr.debugging(Debug::PARSER))
1049 lex.printTable(lyxerr);
1051 while (lex.isOK()) {
1052 switch (lex.lex()) {
1055 string const file = lex.getString();
1056 if (!readUIFile(file))
1061 menubackend.read(lex);
1065 toolbarbackend.read(lex);
1069 toolbarbackend.readToolbars(lex);
1073 if (!rtrim(lex.getString()).empty())
1074 lex.printError("LyX::ReadUIFile: "
1075 "Unknown menu tag: `$$Token'");
1083 // Read the languages file `name'
1084 bool LyX::readLanguagesFile(string const & name)
1086 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1088 string const lang_path = libFileSearch(string(), name);
1089 if (lang_path.empty()) {
1090 showFileError(name);
1093 languages.read(lang_path);
1098 // Read the encodings file `name'
1099 bool LyX::readEncodingsFile(string const & name)
1101 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1103 string const enc_path = libFileSearch(string(), name);
1104 if (enc_path.empty()) {
1105 showFileError(name);
1108 encodings.read(enc_path);
1117 /// return the the number of arguments consumed
1118 typedef boost::function<int(string const &, string const &)> cmd_helper;
1120 int parse_dbg(string const & arg, string const &)
1123 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1124 Debug::showTags(lyxerr);
1127 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1129 lyxerr.level(Debug::value(arg));
1130 Debug::showLevel(lyxerr, lyxerr.level());
1135 int parse_help(string const &, string const &)
1138 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1139 "Command line switches (case sensitive):\n"
1140 "\t-help summarize LyX usage\n"
1141 "\t-userdir dir set user directory to dir\n"
1142 "\t-sysdir dir set system directory to dir\n"
1143 "\t-geometry WxH+X+Y set geometry of the main window\n"
1144 "\t-dbg feature[,feature]...\n"
1145 " select the features to debug.\n"
1146 " Type `lyx -dbg' to see the list of features\n"
1147 "\t-x [--execute] command\n"
1148 " where command is a lyx command.\n"
1149 "\t-e [--export] fmt\n"
1150 " where fmt is the export format of choice.\n"
1151 "\t-i [--import] fmt file.xxx\n"
1152 " where fmt is the import format of choice\n"
1153 " and file.xxx is the file to be imported.\n"
1154 "\t-version summarize version and build info\n"
1155 "Check the LyX man page for more details.")) << endl;
1160 int parse_version(string const &, string const &)
1162 lyxerr << "LyX " << lyx_version
1163 << " (" << lyx_release_date << ")" << endl;
1164 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1166 lyxerr << lyx_version_info << endl;
1171 int parse_sysdir(string const & arg, string const &)
1174 lyxerr << to_utf8(_("Missing directory for -sysdir switch")) << endl;
1177 cl_system_support = arg;
1181 int parse_userdir(string const & arg, string const &)
1184 lyxerr << to_utf8(_("Missing directory for -userdir switch")) << endl;
1187 cl_user_support = arg;
1191 int parse_execute(string const & arg, string const &)
1194 lyxerr << to_utf8(_("Missing command string after --execute switch")) << endl;
1201 int parse_export(string const & type, string const &)
1204 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1205 "--export switch")) << endl;
1208 batch = "buffer-export " + type;
1213 int parse_import(string const & type, string const & file)
1216 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1217 "--import switch")) << endl;
1221 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1225 batch = "buffer-import " + type + ' ' + file;
1232 void LyX::easyParse(int & argc, char * argv[])
1234 std::map<string, cmd_helper> cmdmap;
1236 cmdmap["-dbg"] = parse_dbg;
1237 cmdmap["-help"] = parse_help;
1238 cmdmap["--help"] = parse_help;
1239 cmdmap["-version"] = parse_version;
1240 cmdmap["--version"] = parse_version;
1241 cmdmap["-sysdir"] = parse_sysdir;
1242 cmdmap["-userdir"] = parse_userdir;
1243 cmdmap["-x"] = parse_execute;
1244 cmdmap["--execute"] = parse_execute;
1245 cmdmap["-e"] = parse_export;
1246 cmdmap["--export"] = parse_export;
1247 cmdmap["-i"] = parse_import;
1248 cmdmap["--import"] = parse_import;
1250 for (int i = 1; i < argc; ++i) {
1251 std::map<string, cmd_helper>::const_iterator it
1252 = cmdmap.find(argv[i]);
1254 // check for X11 -geometry option
1255 if (support::compare(argv[i], "-geometry") == 0)
1256 geometryOption_ = true;
1258 // don't complain if not found - may be parsed later
1259 if (it == cmdmap.end())
1262 string arg((i + 1 < argc) ? argv[i + 1] : "");
1263 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1265 int const remove = 1 + it->second(arg, arg2);
1267 // Now, remove used arguments by shifting
1268 // the following ones remove places down.
1270 for (int j = i; j < argc; ++j)
1271 argv[j] = argv[j + remove];
1275 batch_command = batch;
1279 FuncStatus getStatus(FuncRequest const & action)
1281 return LyX::ref().lyxFunc().getStatus(action);
1285 void dispatch(FuncRequest const & action)
1287 LyX::ref().lyxFunc().dispatch(action);
1291 BufferList & theBufferList()
1293 return LyX::ref().bufferList();
1297 LyXFunc & theLyXFunc()
1299 return LyX::ref().lyxFunc();
1303 LyXServer & theLyXServer()
1305 // FIXME: this should not be use_gui dependent
1306 BOOST_ASSERT(use_gui);
1307 return LyX::ref().server();
1311 LyXServerSocket & theLyXServerSocket()
1313 // FIXME: this should not be use_gui dependent
1314 BOOST_ASSERT(use_gui);
1315 return LyX::ref().socket();
1319 kb_keymap & theTopLevelKeymap()
1321 BOOST_ASSERT(use_gui);
1322 return LyX::ref().topLevelKeymap();