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"
60 #include "support/unicode.h"
62 #include <boost/bind.hpp>
63 #include <boost/filesystem/operations.hpp>
71 using support::addName;
72 using support::addPath;
73 using support::bformat;
74 using support::createDirectory;
75 using support::createLyXTmpDir;
76 using support::destroyDir;
77 using support::fileSearch;
78 using support::getEnv;
79 using support::i18nLibFileSearch;
80 using support::libFileSearch;
81 using support::package;
82 using support::prependEnvPath;
84 using support::Systemcall;
86 namespace Alert = frontend::Alert;
87 namespace os = support::os;
88 namespace fs = boost::filesystem;
95 #ifndef CXX_GLOBAL_CSTD
102 frontend::Application * theApp = 0;
104 /// are we using the GUI at all?
106 * We default to true and this is changed to false when the export feature is used.
113 // Filled with the command line arguments "foo" of "-sysdir foo" or
115 string cl_system_support;
116 string cl_user_support;
118 LyX * singleton_ = 0;
120 void showFileError(string const & error)
122 Alert::warning(_("Could not read configuration file"),
123 bformat(_("Error while reading the configuration file\n%1$s.\n"
124 "Please check your installation."), from_utf8(error)));
128 void reconfigureUserLyXDir()
130 string const configure_command = package().configure_command();
132 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
133 support::Path p(package().user_support());
135 one.startscript(Systemcall::Wait, configure_command);
136 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
142 /// The main application class private implementation.
143 struct LyX::Singletons
145 Singletons(): iconv(ucs4_codeset, "UTF-8")
148 /// our function handler
151 BufferList buffer_list_;
153 boost::scoped_ptr<kb_keymap> toplevel_keymap_;
155 boost::scoped_ptr<LyXServer> lyx_server_;
157 boost::scoped_ptr<LyXServerSocket> lyx_socket_;
159 boost::scoped_ptr<frontend::Application> application_;
160 /// lyx session, containing lastfiles, lastfilepos, and lastopened
161 boost::scoped_ptr<Session> session_;
164 IconvProcessor iconv;
170 // Static data are not treated in the same way at all on the Mac (and
171 // the LyX singleton has static methods). This is the reason why the
172 // exit command on the Mac bypasses our dispatch machinery altogether.
173 // On Linux and Windows we won't pass a second time through quit()
174 // because quitting will already be set to true.
182 BOOST_ASSERT(singleton_);
187 LyX const & LyX::cref()
189 BOOST_ASSERT(singleton_);
195 : first_start(false), geometryOption_(false)
198 pimpl_.reset(new Singletons);
202 BufferList & LyX::bufferList()
204 return pimpl_->buffer_list_;
208 BufferList const & LyX::bufferList() const
210 return pimpl_->buffer_list_;
214 Session & LyX::session()
216 BOOST_ASSERT(pimpl_->session_.get());
217 return *pimpl_->session_.get();
221 Session const & LyX::session() const
223 BOOST_ASSERT(pimpl_->session_.get());
224 return *pimpl_->session_.get();
228 LyXFunc & LyX::lyxFunc()
230 return pimpl_->lyxfunc_;
234 LyXFunc const & LyX::lyxFunc() const
236 return pimpl_->lyxfunc_;
240 LyXServer & LyX::server()
242 BOOST_ASSERT(pimpl_->lyx_server_.get());
243 return *pimpl_->lyx_server_.get();
247 LyXServer const & LyX::server() const
249 BOOST_ASSERT(pimpl_->lyx_server_.get());
250 return *pimpl_->lyx_server_.get();
254 LyXServerSocket & LyX::socket()
256 BOOST_ASSERT(pimpl_->lyx_socket_.get());
257 return *pimpl_->lyx_socket_.get();
261 LyXServerSocket const & LyX::socket() const
263 BOOST_ASSERT(pimpl_->lyx_socket_.get());
264 return *pimpl_->lyx_socket_.get();
268 frontend::Application & LyX::application()
270 BOOST_ASSERT(pimpl_->application_.get());
271 return *pimpl_->application_.get();
275 frontend::Application const & LyX::application() const
277 BOOST_ASSERT(pimpl_->application_.get());
278 return *pimpl_->application_.get();
282 kb_keymap & LyX::topLevelKeymap()
284 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
285 return *pimpl_->toplevel_keymap_.get();
289 IconvProcessor & LyX::iconvProcessor()
291 return pimpl_->iconv;
295 kb_keymap const & LyX::topLevelKeymap() const
297 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
298 return *pimpl_->toplevel_keymap_.get();
302 Buffer const * const LyX::updateInset(InsetBase const * inset) const
307 Buffer const * buffer_ptr = 0;
308 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
309 vector<int>::const_iterator it = view_ids.begin();
310 vector<int>::const_iterator const end = view_ids.end();
311 for (; it != end; ++it) {
313 pimpl_->application_->gui().view(*it).updateInset(inset);
321 int LyX::exec(int & argc, char * argv[])
323 // Here we need to parse the command line. At least
324 // we need to parse for "-dbg" and "-help"
325 easyParse(argc, argv);
327 support::init_package(argv[0], cl_system_support, cl_user_support,
328 support::top_build_dir_is_one_level_up);
330 vector<string> files;
333 // FIXME: create a ConsoleApplication
334 int exit_status = loadFiles(argc, argv, files);
341 // Force adding of font path _before_ Application is initialized
342 support::addFontResources();
344 // Let the frontend parse and remove all arguments that it knows
345 pimpl_->application_.reset(createApplication(argc, argv));
346 // FIXME: this global pointer should probably go.
347 theApp = pimpl_->application_.get();
351 // Parse and remove all known arguments in the LyX singleton
352 // Give an error for all remaining ones.
353 int exit_status = loadFiles(argc, argv, files);
355 // Kill the application object before exiting.
356 pimpl_->application_.reset();
362 restoreGuiSession(files);
363 // Start the real execution loop.
366 /* Create a CoreApplication class that will provide the main event loop
367 * and the socket callback registering. With Qt4, only QtCore
368 * library would be needed.
369 * When this is done, a server_mode could be created and the following two
370 * line would be moved out from here.
372 pimpl_->lyx_server_.reset(new LyXServer(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
373 pimpl_->lyx_socket_.reset(new LyXServerSocket(&pimpl_->lyxfunc_,
374 support::os::internal_path(package().temp_dir() + "/lyxsocket")));
376 exit_status = pimpl_->application_->exec();
377 // Kill the application object before exiting. This avoid crash
379 pimpl_->application_.reset();
380 // Restore original font resources after Application is destroyed.
381 support::restoreFontResources();
387 void LyX::prepareExit()
389 // Set a flag that we do quitting from the program,
390 // so no refreshes are necessary.
393 // close buffers first
394 pimpl_->buffer_list_.closeAll();
396 // do any other cleanup procedures now
397 lyxerr[Debug::INFO] << "Deleting tmp dir " << package().temp_dir() << endl;
399 if (!destroyDir(package().temp_dir())) {
400 docstring const msg =
401 bformat(_("Unable to remove the temporary directory %1$s"),
402 from_utf8(package().temp_dir()));
403 Alert::warning(_("Unable to remove temporary directory"), msg);
408 void LyX::earlyExit(int status)
410 BOOST_ASSERT(pimpl_->application_.get());
411 // LyX::pimpl_::application_ is not initialised at this
412 // point so it's safe to just exit after some cleanup.
420 lyxerr[Debug::INFO] << "Running QuitLyX." << endl;
425 pimpl_->session_->writeFile();
426 pimpl_->lyx_server_.reset();
427 pimpl_->lyx_socket_.reset();
428 pimpl_->application_->exit(0);
434 int LyX::loadFiles(int & argc, char * argv[],
435 vector<string> & files)
437 // check for any spurious extra arguments
438 // other than documents
439 for (int argi = 1; argi < argc ; ++argi) {
440 if (argv[argi][0] == '-') {
442 bformat(_("Wrong command line option `%1$s'. Exiting."),
443 from_utf8(argv[argi]))) << endl;
448 // Initialization of LyX (reads lyxrc and more)
449 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
450 bool success = init();
451 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
455 for (int argi = argc - 1; argi >= 1; --argi) {
456 // check for any remaining extra arguments other than
457 // document file names. These will be passed out to the
459 if (argv[argi][0] == '-')
461 files.push_back(os::internal_path(argv[argi]));
465 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
467 Buffer * last_loaded = 0;
469 vector<string>::const_iterator it = files.begin();
470 vector<string>::const_iterator end = files.end();
472 for (; it != end; ++it) {
473 // get absolute path of file and add ".lyx" to
474 // the filename if necessary
475 string s = fileSearch(string(), *it, "lyx");
477 Buffer * const b = newFile(*it, string(), true);
481 Buffer * buf = pimpl_->buffer_list_.newBuffer(s, false);
482 if (loadLyXFile(buf, s)) {
484 ErrorList const & el = buf->errorList("Parse");
486 for_each(el.begin(), el.end(),
487 boost::bind(&LyX::printError, this, _1));
490 pimpl_->buffer_list_.release(buf);
494 files.clear(); // the files are already loaded
500 void LyX::execBatchCommands()
502 // Execute batch commands if available
503 if (batch_command.empty())
506 lyxerr[Debug::INIT] << "About to handle -x '"
507 << batch_command << '\'' << endl;
509 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
513 void LyX::restoreGuiSession(vector<string> const & files)
515 LyXView * view = newLyXView();
518 for_each(files.begin(), files.end(),
519 bind(&LyXView::loadLyXFile, view, _1, true));
521 // if a file is specified, I assume that user wants to edit *that* file
522 if (files.empty() && lyxrc.load_session) {
523 vector<string> const & lastopened = pimpl_->session_->lastOpened().getfiles();
524 // do not add to the lastfile list since these files are restored from
525 // last seesion, and should be already there (regular files), or should
526 // not be added at all (help files).
527 for_each(lastopened.begin(), lastopened.end(),
528 bind(&LyXView::loadLyXFile, view, _1, false));
530 // clear this list to save a few bytes of RAM
531 pimpl_->session_->lastOpened().clear();
535 LyXView * LyX::newLyXView()
540 // determine windows size and position, from lyxrc and/or session
542 unsigned int width = 690;
543 unsigned int height = 510;
544 bool maximize = false;
546 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
547 width = lyxrc.geometry_width;
548 height = lyxrc.geometry_height;
550 // if lyxrc returns (0,0), then use session info
552 string val = session().sessionInfo().load("WindowWidth");
554 width = convert<unsigned int>(val);
555 val = session().sessionInfo().load("WindowHeight");
557 height = convert<unsigned int>(val);
558 if (session().sessionInfo().load("WindowIsMaximized") == "yes")
562 // if user wants to restore window position
565 if (lyxrc.geometry_xysaved) {
566 string val = session().sessionInfo().load("WindowPosX");
568 posx = convert<int>(val);
569 val = session().sessionInfo().load("WindowPosY");
571 posy = convert<int>(val);
574 if (geometryOption_) {
578 // create the main window
579 LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximize);
587 The SIGHUP signal does not exist on Windows and does not need to be handled.
589 Windows handles SIGFPE and SIGSEGV signals as expected.
591 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
592 cause a new thread to be spawned. This may well result in unexpected
593 behaviour by the single-threaded LyX.
595 SIGTERM signals will come only from another process actually sending
596 that signal using 'raise' in Windows' POSIX compatability layer. It will
597 not come from the general "terminate process" methods that everyone
598 actually uses (and which can't be trapped). Killing an app 'politely' on
599 Windows involves first sending a WM_CLOSE message, something that is
600 caught already by the Qt frontend.
602 For more information see:
604 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
605 ...signals are mostly useless on Windows for a variety of reasons that are
608 'UNIX Application Migration Guide, Chapter 9'
609 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
611 'How To Terminate an Application "Cleanly" in Win32'
612 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
616 static void error_handler(int err_sig)
618 // Throw away any signals other than the first one received.
619 static sig_atomic_t handling_error = false;
622 handling_error = true;
624 // We have received a signal indicating a fatal error, so
625 // try and save the data ASAP.
626 LyX::cref().emergencyCleanup();
628 // These lyxerr calls may or may not work:
630 // Signals are asynchronous, so the main program may be in a very
631 // fragile state when a signal is processed and thus while a signal
632 // handler function executes.
633 // In general, therefore, we should avoid performing any
634 // I/O operations or calling most library and system functions from
637 // This shouldn't matter here, however, as we've already invoked
642 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
646 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
649 lyxerr << "\nlyx: SIGSEGV signal caught\n"
650 "Sorry, you have found a bug in LyX. "
651 "Please read the bug-reporting instructions "
652 "in Help->Introduction and send us a bug report, "
653 "if necessary. Thanks !\nBye." << endl;
661 // Deinstall the signal handlers
663 signal(SIGHUP, SIG_DFL);
665 signal(SIGINT, SIG_DFL);
666 signal(SIGFPE, SIG_DFL);
667 signal(SIGSEGV, SIG_DFL);
668 signal(SIGTERM, SIG_DFL);
671 if (err_sig == SIGSEGV ||
672 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
674 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
683 void LyX::printError(ErrorItem const & ei)
685 docstring tmp = _("LyX: ") + ei.error + char_type(':')
687 std::cerr << to_utf8(tmp) << std::endl;
691 void LyX::initGuiFont()
693 if (lyxrc.roman_font_name.empty())
694 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
696 if (lyxrc.sans_font_name.empty())
697 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
699 if (lyxrc.typewriter_font_name.empty())
700 lyxrc.typewriter_font_name
701 = pimpl_->application_->typewriterFontName();
708 signal(SIGHUP, error_handler);
710 signal(SIGFPE, error_handler);
711 signal(SIGSEGV, error_handler);
712 signal(SIGINT, error_handler);
713 signal(SIGTERM, error_handler);
714 // SIGPIPE can be safely ignored.
716 lyxrc.tempdir_path = package().temp_dir();
717 lyxrc.document_path = package().document_dir();
719 if (lyxrc.template_path.empty()) {
720 lyxrc.template_path = addPath(package().system_support(),
725 // Read configuration files
728 // This one may have been distributed along with LyX.
729 if (!readRcFile("lyxrc.dist"))
732 // Set the PATH correctly.
733 #if !defined (USE_POSIX_PACKAGING)
734 // Add the directory containing the LyX executable to the path
735 // so that LyX can find things like tex2lyx.
736 if (package().build_support().empty())
737 prependEnvPath("PATH", package().binary_dir());
739 if (!lyxrc.path_prefix.empty())
740 prependEnvPath("PATH", lyxrc.path_prefix);
742 // Check that user LyX directory is ok.
743 if (queryUserLyXDir(package().explicit_user_support()))
744 reconfigureUserLyXDir();
746 // no need for a splash when there is no GUI
751 // This one is generated in user_support directory by lib/configure.py.
752 if (!readRcFile("lyxrc.defaults"))
755 // Query the OS to know what formats are viewed natively
756 formats.setAutoOpen();
758 // Read lyxrc.dist again to be able to override viewer auto-detection.
759 readRcFile("lyxrc.dist");
761 system_lyxrc = lyxrc;
762 system_formats = formats;
763 system_converters = converters;
764 system_movers = movers;
765 system_lcolor = lcolor;
767 // This one is edited through the preferences dialog.
768 if (!readRcFile("preferences"))
771 if (!readEncodingsFile("encodings"))
773 if (!readLanguagesFile("languages"))
777 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
783 pimpl_->toplevel_keymap_.reset(new kb_keymap);
784 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
785 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
787 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
790 if (!readUIFile(lyxrc.ui_file))
794 if (lyxerr.debugging(Debug::LYXRC))
797 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
798 if (!lyxrc.path_prefix.empty())
799 prependEnvPath("PATH", lyxrc.path_prefix);
801 if (fs::exists(lyxrc.document_path) &&
802 fs::is_directory(lyxrc.document_path))
803 package().document_dir() = lyxrc.document_path;
805 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
806 if (package().temp_dir().empty()) {
807 Alert::error(_("Could not create temporary directory"),
808 bformat(_("Could not create a temporary directory in\n"
809 "%1$s. Make sure that this\n"
810 "path exists and is writable and try again."),
811 from_utf8(lyxrc.tempdir_path)));
812 // createLyXTmpDir() tries sufficiently hard to create a
813 // usable temp dir, so the probability to come here is
814 // close to zero. We therefore don't try to overcome this
815 // problem with e.g. asking the user for a new path and
816 // trying again but simply exit.
820 if (lyxerr.debugging(Debug::INIT)) {
821 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
824 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
825 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
827 // This must happen after package initialization and after lyxrc is
828 // read, therefore it can't be done by a static object.
829 ConverterCache::init();
835 void LyX::defaultKeyBindings(kb_keymap * kbmap)
837 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
838 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
839 kbmap->bind("Up", FuncRequest(LFUN_UP));
840 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
842 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
843 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
844 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
845 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
847 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
848 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
849 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
850 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
852 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
853 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
855 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
856 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
858 // kbmap->bindings to enable the use of the numeric keypad
860 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
861 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
862 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
863 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
864 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
865 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
866 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
867 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
868 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
869 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
870 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
871 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
872 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
873 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
874 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
875 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
876 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
877 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
878 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
879 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
880 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
881 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
882 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
883 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
887 void LyX::emergencyCleanup() const
889 // what to do about tmpfiles is non-obvious. we would
890 // like to delete any we find, but our lyxdir might
891 // contain documents etc. which might be helpful on
894 pimpl_->buffer_list_.emergencyWriteAll();
896 pimpl_->lyx_server_->emergencyCleanup();
897 pimpl_->lyx_server_.reset();
898 pimpl_->lyx_socket_.reset();
903 void LyX::deadKeyBindings(kb_keymap * kbmap)
905 // bindKeyings for transparent handling of deadkeys
906 // The keysyms are gotten from XFree86 X11R6
907 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
908 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
909 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
910 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
911 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
912 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
913 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
914 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
915 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
916 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
917 // nothing with this name
918 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
919 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
920 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
921 // nothing with this name either...
922 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
923 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
924 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
925 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
931 // return true if file does not exist or is older than configure.py.
932 bool needsUpdate(string const & file)
934 static string const configure_script =
935 addName(package().system_support(), "configure.py");
936 string const absfile =
937 addName(package().user_support(), file);
939 return (! fs::exists(absfile))
940 || (fs::last_write_time(configure_script)
941 > fs::last_write_time(absfile));
947 bool LyX::queryUserLyXDir(bool explicit_userdir)
949 // Does user directory exist?
950 if (fs::exists(package().user_support()) &&
951 fs::is_directory(package().user_support())) {
954 return needsUpdate("lyxrc.defaults")
955 || needsUpdate("textclass.lst")
956 || needsUpdate("packages.lst");
959 first_start = !explicit_userdir;
961 // If the user specified explicitly a directory, ask whether
962 // to create it. If the user says "no", then exit.
963 if (explicit_userdir &&
965 _("Missing user LyX directory"),
966 bformat(_("You have specified a non-existent user "
967 "LyX directory, %1$s.\n"
968 "It is needed to keep your own configuration."),
969 from_utf8(package().user_support())),
971 _("&Create directory"),
973 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
974 earlyExit(EXIT_FAILURE);
977 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
978 from_utf8(package().user_support())))
981 if (!createDirectory(package().user_support(), 0755)) {
982 // Failed, so let's exit.
983 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
985 earlyExit(EXIT_FAILURE);
992 bool LyX::readRcFile(string const & name)
994 lyxerr[Debug::INIT] << "About to read " << name << "... ";
996 string const lyxrc_path = libFileSearch(string(), name);
997 if (!lyxrc_path.empty()) {
999 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
1001 if (lyxrc.read(lyxrc_path) < 0) {
1002 showFileError(name);
1006 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
1012 // Read the ui file `name'
1013 bool LyX::readUIFile(string const & name)
1023 struct keyword_item uitags[ui_last - 1] = {
1024 { "include", ui_include },
1025 { "menuset", ui_menuset },
1026 { "toolbar", ui_toolbar },
1027 { "toolbars", ui_toolbars }
1030 // Ensure that a file is read only once (prevents include loops)
1031 static std::list<string> uifiles;
1032 std::list<string>::const_iterator it = uifiles.begin();
1033 std::list<string>::const_iterator end = uifiles.end();
1034 it = std::find(it, end, name);
1036 lyxerr[Debug::INIT] << "UI file '" << name
1037 << "' has been read already. "
1038 << "Is this an include loop?"
1043 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1045 string const ui_path = libFileSearch("ui", name, "ui");
1047 if (ui_path.empty()) {
1048 lyxerr[Debug::INIT] << "Could not find " << name << endl;
1049 showFileError(name);
1052 uifiles.push_back(name);
1054 lyxerr[Debug::INIT] << "Found " << name
1055 << " in " << ui_path << endl;
1056 LyXLex lex(uitags, ui_last - 1);
1057 lex.setFile(ui_path);
1059 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1063 if (lyxerr.debugging(Debug::PARSER))
1064 lex.printTable(lyxerr);
1066 while (lex.isOK()) {
1067 switch (lex.lex()) {
1070 string const file = lex.getString();
1071 if (!readUIFile(file))
1076 menubackend.read(lex);
1080 toolbarbackend.read(lex);
1084 toolbarbackend.readToolbars(lex);
1088 if (!rtrim(lex.getString()).empty())
1089 lex.printError("LyX::ReadUIFile: "
1090 "Unknown menu tag: `$$Token'");
1098 // Read the languages file `name'
1099 bool LyX::readLanguagesFile(string const & name)
1101 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1103 string const lang_path = libFileSearch(string(), name);
1104 if (lang_path.empty()) {
1105 showFileError(name);
1108 languages.read(lang_path);
1113 // Read the encodings file `name'
1114 bool LyX::readEncodingsFile(string const & name)
1116 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1118 string const enc_path = libFileSearch(string(), name);
1119 if (enc_path.empty()) {
1120 showFileError(name);
1123 encodings.read(enc_path);
1132 /// return the the number of arguments consumed
1133 typedef boost::function<int(string const &, string const &)> cmd_helper;
1135 int parse_dbg(string const & arg, string const &)
1138 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1139 Debug::showTags(lyxerr);
1142 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1144 lyxerr.level(Debug::value(arg));
1145 Debug::showLevel(lyxerr, lyxerr.level());
1150 int parse_help(string const &, string const &)
1153 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1154 "Command line switches (case sensitive):\n"
1155 "\t-help summarize LyX usage\n"
1156 "\t-userdir dir set user directory to dir\n"
1157 "\t-sysdir dir set system directory to dir\n"
1158 "\t-geometry WxH+X+Y set geometry of the main window\n"
1159 "\t-dbg feature[,feature]...\n"
1160 " select the features to debug.\n"
1161 " Type `lyx -dbg' to see the list of features\n"
1162 "\t-x [--execute] command\n"
1163 " where command is a lyx command.\n"
1164 "\t-e [--export] fmt\n"
1165 " where fmt is the export format of choice.\n"
1166 "\t-i [--import] fmt file.xxx\n"
1167 " where fmt is the import format of choice\n"
1168 " and file.xxx is the file to be imported.\n"
1169 "\t-version summarize version and build info\n"
1170 "Check the LyX man page for more details.")) << endl;
1175 int parse_version(string const &, string const &)
1177 lyxerr << "LyX " << lyx_version
1178 << " (" << lyx_release_date << ")" << endl;
1179 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1181 lyxerr << lyx_version_info << endl;
1186 int parse_sysdir(string const & arg, string const &)
1189 lyxerr << to_utf8(_("Missing directory for -sysdir switch")) << endl;
1192 cl_system_support = arg;
1196 int parse_userdir(string const & arg, string const &)
1199 lyxerr << to_utf8(_("Missing directory for -userdir switch")) << endl;
1202 cl_user_support = arg;
1206 int parse_execute(string const & arg, string const &)
1209 lyxerr << to_utf8(_("Missing command string after --execute switch")) << endl;
1216 int parse_export(string const & type, string const &)
1219 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1220 "--export switch")) << endl;
1223 batch = "buffer-export " + type;
1228 int parse_import(string const & type, string const & file)
1231 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1232 "--import switch")) << endl;
1236 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1240 batch = "buffer-import " + type + ' ' + file;
1247 void LyX::easyParse(int & argc, char * argv[])
1249 std::map<string, cmd_helper> cmdmap;
1251 cmdmap["-dbg"] = parse_dbg;
1252 cmdmap["-help"] = parse_help;
1253 cmdmap["--help"] = parse_help;
1254 cmdmap["-version"] = parse_version;
1255 cmdmap["--version"] = parse_version;
1256 cmdmap["-sysdir"] = parse_sysdir;
1257 cmdmap["-userdir"] = parse_userdir;
1258 cmdmap["-x"] = parse_execute;
1259 cmdmap["--execute"] = parse_execute;
1260 cmdmap["-e"] = parse_export;
1261 cmdmap["--export"] = parse_export;
1262 cmdmap["-i"] = parse_import;
1263 cmdmap["--import"] = parse_import;
1265 for (int i = 1; i < argc; ++i) {
1266 std::map<string, cmd_helper>::const_iterator it
1267 = cmdmap.find(argv[i]);
1269 // check for X11 -geometry option
1270 if (support::compare(argv[i], "-geometry") == 0)
1271 geometryOption_ = true;
1273 // don't complain if not found - may be parsed later
1274 if (it == cmdmap.end())
1277 string arg((i + 1 < argc) ? argv[i + 1] : "");
1278 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1280 int const remove = 1 + it->second(arg, arg2);
1282 // Now, remove used arguments by shifting
1283 // the following ones remove places down.
1285 for (int j = i; j < argc; ++j)
1286 argv[j] = argv[j + remove];
1290 batch_command = batch;
1294 FuncStatus getStatus(FuncRequest const & action)
1296 return LyX::ref().lyxFunc().getStatus(action);
1300 void dispatch(FuncRequest const & action)
1302 LyX::ref().lyxFunc().dispatch(action);
1306 BufferList & theBufferList()
1308 return LyX::ref().bufferList();
1312 LyXFunc & theLyXFunc()
1314 return LyX::ref().lyxFunc();
1318 LyXServer & theLyXServer()
1320 // FIXME: this should not be use_gui dependent
1321 BOOST_ASSERT(use_gui);
1322 return LyX::ref().server();
1326 LyXServerSocket & theLyXServerSocket()
1328 // FIXME: this should not be use_gui dependent
1329 BOOST_ASSERT(use_gui);
1330 return LyX::ref().socket();
1334 kb_keymap & theTopLevelKeymap()
1336 BOOST_ASSERT(use_gui);
1337 return LyX::ref().topLevelKeymap();
1341 IconvProcessor & utf8ToUcs4()
1343 return LyX::ref().iconvProcessor();