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);
340 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
345 BufferList::iterator begin = pimpl_->buffer_list_.begin();
346 BufferList::iterator end = pimpl_->buffer_list_.end();
348 bool final_success = false;
349 for (BufferList::iterator I = begin; I != end; ++I) {
351 bool success = false;
352 buf->dispatch(batch_command, &success);
353 final_success |= success;
356 return !final_success;
359 // Force adding of font path _before_ Application is initialized
360 support::addFontResources();
362 // Let the frontend parse and remove all arguments that it knows
363 pimpl_->application_.reset(createApplication(argc, argv));
364 // FIXME: this global pointer should probably go.
365 theApp = pimpl_->application_.get();
369 // Parse and remove all known arguments in the LyX singleton
370 // Give an error for all remaining ones.
371 int exit_status = loadFiles(argc, argv, files);
373 // Kill the application object before exiting.
374 pimpl_->application_.reset();
380 restoreGuiSession(files);
381 // Start the real execution loop.
384 /* Create a CoreApplication class that will provide the main event loop
385 * and the socket callback registering. With Qt4, only QtCore
386 * library would be needed.
387 * When this is done, a server_mode could be created and the following two
388 * line would be moved out from here.
390 pimpl_->lyx_server_.reset(new LyXServer(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
391 pimpl_->lyx_socket_.reset(new LyXServerSocket(&pimpl_->lyxfunc_,
392 support::os::internal_path(package().temp_dir() + "/lyxsocket")));
394 exit_status = pimpl_->application_->exec();
395 // Kill the application object before exiting. This avoid crash
397 pimpl_->application_.reset();
398 // Restore original font resources after Application is destroyed.
399 support::restoreFontResources();
405 void LyX::prepareExit()
407 // Set a flag that we do quitting from the program,
408 // so no refreshes are necessary.
411 // close buffers first
412 pimpl_->buffer_list_.closeAll();
414 // do any other cleanup procedures now
415 lyxerr[Debug::INFO] << "Deleting tmp dir " << package().temp_dir() << endl;
417 if (!destroyDir(package().temp_dir())) {
418 docstring const msg =
419 bformat(_("Unable to remove the temporary directory %1$s"),
420 from_utf8(package().temp_dir()));
421 Alert::warning(_("Unable to remove temporary directory"), msg);
426 void LyX::earlyExit(int status)
428 BOOST_ASSERT(pimpl_->application_.get());
429 // LyX::pimpl_::application_ is not initialised at this
430 // point so it's safe to just exit after some cleanup.
438 lyxerr[Debug::INFO] << "Running QuitLyX." << endl;
443 pimpl_->session_->writeFile();
444 pimpl_->lyx_server_.reset();
445 pimpl_->lyx_socket_.reset();
446 pimpl_->application_->exit(0);
452 int LyX::loadFiles(int & argc, char * argv[],
453 vector<string> & files)
455 // check for any spurious extra arguments
456 // other than documents
457 for (int argi = 1; argi < argc ; ++argi) {
458 if (argv[argi][0] == '-') {
460 bformat(_("Wrong command line option `%1$s'. Exiting."),
461 from_utf8(argv[argi]))) << endl;
466 // Initialization of LyX (reads lyxrc and more)
467 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
468 bool success = init();
469 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
473 for (int argi = argc - 1; argi >= 1; --argi) {
474 // check for any remaining extra arguments other than
475 // document file names. These will be passed out to the
477 if (argv[argi][0] == '-')
479 files.push_back(os::internal_path(argv[argi]));
483 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
485 Buffer * last_loaded = 0;
487 vector<string>::const_iterator it = files.begin();
488 vector<string>::const_iterator end = files.end();
490 for (; it != end; ++it) {
491 // get absolute path of file and add ".lyx" to
492 // the filename if necessary
493 string s = fileSearch(string(), *it, "lyx");
495 Buffer * const b = newFile(*it, string(), true);
499 Buffer * buf = pimpl_->buffer_list_.newBuffer(s, false);
500 if (loadLyXFile(buf, s)) {
502 ErrorList const & el = buf->errorList("Parse");
504 for_each(el.begin(), el.end(),
505 boost::bind(&LyX::printError, this, _1));
508 pimpl_->buffer_list_.release(buf);
512 files.clear(); // the files are already loaded
518 void LyX::execBatchCommands()
520 // Execute batch commands if available
521 if (batch_command.empty())
524 lyxerr[Debug::INIT] << "About to handle -x '"
525 << batch_command << '\'' << endl;
527 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
531 void LyX::restoreGuiSession(vector<string> const & files)
533 LyXView * view = newLyXView();
536 for_each(files.begin(), files.end(),
537 bind(&LyXView::loadLyXFile, view, _1, true));
539 // if a file is specified, I assume that user wants to edit *that* file
540 if (files.empty() && lyxrc.load_session) {
541 vector<string> const & lastopened = pimpl_->session_->lastOpened().getfiles();
542 // do not add to the lastfile list since these files are restored from
543 // last seesion, and should be already there (regular files), or should
544 // not be added at all (help files).
545 for_each(lastopened.begin(), lastopened.end(),
546 bind(&LyXView::loadLyXFile, view, _1, false));
548 // clear this list to save a few bytes of RAM
549 pimpl_->session_->lastOpened().clear();
553 LyXView * LyX::newLyXView()
558 // determine windows size and position, from lyxrc and/or session
560 unsigned int width = 690;
561 unsigned int height = 510;
562 bool maximize = false;
564 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
565 width = lyxrc.geometry_width;
566 height = lyxrc.geometry_height;
568 // if lyxrc returns (0,0), then use session info
570 string val = session().sessionInfo().load("WindowWidth");
572 width = convert<unsigned int>(val);
573 val = session().sessionInfo().load("WindowHeight");
575 height = convert<unsigned int>(val);
576 if (session().sessionInfo().load("WindowIsMaximized") == "yes")
580 // if user wants to restore window position
583 if (lyxrc.geometry_xysaved) {
584 string val = session().sessionInfo().load("WindowPosX");
586 posx = convert<int>(val);
587 val = session().sessionInfo().load("WindowPosY");
589 posy = convert<int>(val);
592 if (geometryOption_) {
596 // create the main window
597 LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximize);
605 The SIGHUP signal does not exist on Windows and does not need to be handled.
607 Windows handles SIGFPE and SIGSEGV signals as expected.
609 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
610 cause a new thread to be spawned. This may well result in unexpected
611 behaviour by the single-threaded LyX.
613 SIGTERM signals will come only from another process actually sending
614 that signal using 'raise' in Windows' POSIX compatability layer. It will
615 not come from the general "terminate process" methods that everyone
616 actually uses (and which can't be trapped). Killing an app 'politely' on
617 Windows involves first sending a WM_CLOSE message, something that is
618 caught already by the Qt frontend.
620 For more information see:
622 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
623 ...signals are mostly useless on Windows for a variety of reasons that are
626 'UNIX Application Migration Guide, Chapter 9'
627 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
629 'How To Terminate an Application "Cleanly" in Win32'
630 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
634 static void error_handler(int err_sig)
636 // Throw away any signals other than the first one received.
637 static sig_atomic_t handling_error = false;
640 handling_error = true;
642 // We have received a signal indicating a fatal error, so
643 // try and save the data ASAP.
644 LyX::cref().emergencyCleanup();
646 // These lyxerr calls may or may not work:
648 // Signals are asynchronous, so the main program may be in a very
649 // fragile state when a signal is processed and thus while a signal
650 // handler function executes.
651 // In general, therefore, we should avoid performing any
652 // I/O operations or calling most library and system functions from
655 // This shouldn't matter here, however, as we've already invoked
660 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
664 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
667 lyxerr << "\nlyx: SIGSEGV signal caught\n"
668 "Sorry, you have found a bug in LyX. "
669 "Please read the bug-reporting instructions "
670 "in Help->Introduction and send us a bug report, "
671 "if necessary. Thanks !\nBye." << endl;
679 // Deinstall the signal handlers
681 signal(SIGHUP, SIG_DFL);
683 signal(SIGINT, SIG_DFL);
684 signal(SIGFPE, SIG_DFL);
685 signal(SIGSEGV, SIG_DFL);
686 signal(SIGTERM, SIG_DFL);
689 if (err_sig == SIGSEGV ||
690 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
692 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
701 void LyX::printError(ErrorItem const & ei)
703 docstring tmp = _("LyX: ") + ei.error + char_type(':')
705 std::cerr << to_utf8(tmp) << std::endl;
709 void LyX::initGuiFont()
711 if (lyxrc.roman_font_name.empty())
712 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
714 if (lyxrc.sans_font_name.empty())
715 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
717 if (lyxrc.typewriter_font_name.empty())
718 lyxrc.typewriter_font_name
719 = pimpl_->application_->typewriterFontName();
726 signal(SIGHUP, error_handler);
728 signal(SIGFPE, error_handler);
729 signal(SIGSEGV, error_handler);
730 signal(SIGINT, error_handler);
731 signal(SIGTERM, error_handler);
732 // SIGPIPE can be safely ignored.
734 lyxrc.tempdir_path = package().temp_dir();
735 lyxrc.document_path = package().document_dir();
737 if (lyxrc.template_path.empty()) {
738 lyxrc.template_path = addPath(package().system_support(),
743 // Read configuration files
746 // This one may have been distributed along with LyX.
747 if (!readRcFile("lyxrc.dist"))
750 // Set the PATH correctly.
751 #if !defined (USE_POSIX_PACKAGING)
752 // Add the directory containing the LyX executable to the path
753 // so that LyX can find things like tex2lyx.
754 if (package().build_support().empty())
755 prependEnvPath("PATH", package().binary_dir());
757 if (!lyxrc.path_prefix.empty())
758 prependEnvPath("PATH", lyxrc.path_prefix);
760 // Check that user LyX directory is ok.
761 if (queryUserLyXDir(package().explicit_user_support()))
762 reconfigureUserLyXDir();
764 // no need for a splash when there is no GUI
769 // This one is generated in user_support directory by lib/configure.py.
770 if (!readRcFile("lyxrc.defaults"))
773 // Query the OS to know what formats are viewed natively
774 formats.setAutoOpen();
776 // Read lyxrc.dist again to be able to override viewer auto-detection.
777 readRcFile("lyxrc.dist");
779 system_lyxrc = lyxrc;
780 system_formats = formats;
781 system_converters = converters;
782 system_movers = movers;
783 system_lcolor = lcolor;
785 // This one is edited through the preferences dialog.
786 if (!readRcFile("preferences"))
789 if (!readEncodingsFile("encodings"))
791 if (!readLanguagesFile("languages"))
795 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
801 pimpl_->toplevel_keymap_.reset(new kb_keymap);
802 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
803 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
805 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
808 if (!readUIFile(lyxrc.ui_file))
812 if (lyxerr.debugging(Debug::LYXRC))
815 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
816 if (!lyxrc.path_prefix.empty())
817 prependEnvPath("PATH", lyxrc.path_prefix);
819 if (fs::exists(lyxrc.document_path) &&
820 fs::is_directory(lyxrc.document_path))
821 package().document_dir() = lyxrc.document_path;
823 package().temp_dir() = createLyXTmpDir(lyxrc.tempdir_path);
824 if (package().temp_dir().empty()) {
825 Alert::error(_("Could not create temporary directory"),
826 bformat(_("Could not create a temporary directory in\n"
827 "%1$s. Make sure that this\n"
828 "path exists and is writable and try again."),
829 from_utf8(lyxrc.tempdir_path)));
830 // createLyXTmpDir() tries sufficiently hard to create a
831 // usable temp dir, so the probability to come here is
832 // close to zero. We therefore don't try to overcome this
833 // problem with e.g. asking the user for a new path and
834 // trying again but simply exit.
838 if (lyxerr.debugging(Debug::INIT)) {
839 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
842 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
843 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
845 // This must happen after package initialization and after lyxrc is
846 // read, therefore it can't be done by a static object.
847 ConverterCache::init();
853 void LyX::defaultKeyBindings(kb_keymap * kbmap)
855 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
856 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
857 kbmap->bind("Up", FuncRequest(LFUN_UP));
858 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
860 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
861 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
862 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
863 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
865 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
866 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
867 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
868 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
870 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
871 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
873 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
874 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
876 // kbmap->bindings to enable the use of the numeric keypad
878 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
879 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
880 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
881 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
882 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
883 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
884 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
885 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
886 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
887 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
888 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
889 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
890 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
891 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
892 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
893 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
894 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
895 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
896 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
897 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
898 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
899 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
900 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
901 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
905 void LyX::emergencyCleanup() const
907 // what to do about tmpfiles is non-obvious. we would
908 // like to delete any we find, but our lyxdir might
909 // contain documents etc. which might be helpful on
912 pimpl_->buffer_list_.emergencyWriteAll();
914 pimpl_->lyx_server_->emergencyCleanup();
915 pimpl_->lyx_server_.reset();
916 pimpl_->lyx_socket_.reset();
921 void LyX::deadKeyBindings(kb_keymap * kbmap)
923 // bindKeyings for transparent handling of deadkeys
924 // The keysyms are gotten from XFree86 X11R6
925 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
926 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
927 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
928 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
929 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
930 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
931 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
932 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
933 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
934 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
935 // nothing with this name
936 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
937 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
938 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
939 // nothing with this name either...
940 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
941 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
942 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
943 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
949 // return true if file does not exist or is older than configure.py.
950 bool needsUpdate(string const & file)
952 static string const configure_script =
953 addName(package().system_support(), "configure.py");
954 string const absfile =
955 addName(package().user_support(), file);
957 return (! fs::exists(absfile))
958 || (fs::last_write_time(configure_script)
959 > fs::last_write_time(absfile));
965 bool LyX::queryUserLyXDir(bool explicit_userdir)
967 // Does user directory exist?
968 if (fs::exists(package().user_support()) &&
969 fs::is_directory(package().user_support())) {
972 return needsUpdate("lyxrc.defaults")
973 || needsUpdate("textclass.lst")
974 || needsUpdate("packages.lst");
977 first_start = !explicit_userdir;
979 // If the user specified explicitly a directory, ask whether
980 // to create it. If the user says "no", then exit.
981 if (explicit_userdir &&
983 _("Missing user LyX directory"),
984 bformat(_("You have specified a non-existent user "
985 "LyX directory, %1$s.\n"
986 "It is needed to keep your own configuration."),
987 from_utf8(package().user_support())),
989 _("&Create directory"),
991 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
992 earlyExit(EXIT_FAILURE);
995 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
996 from_utf8(package().user_support())))
999 if (!createDirectory(package().user_support(), 0755)) {
1000 // Failed, so let's exit.
1001 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1003 earlyExit(EXIT_FAILURE);
1010 bool LyX::readRcFile(string const & name)
1012 lyxerr[Debug::INIT] << "About to read " << name << "... ";
1014 string const lyxrc_path = libFileSearch(string(), name);
1015 if (!lyxrc_path.empty()) {
1017 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
1019 if (lyxrc.read(lyxrc_path) < 0) {
1020 showFileError(name);
1024 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
1030 // Read the ui file `name'
1031 bool LyX::readUIFile(string const & name)
1041 struct keyword_item uitags[ui_last - 1] = {
1042 { "include", ui_include },
1043 { "menuset", ui_menuset },
1044 { "toolbar", ui_toolbar },
1045 { "toolbars", ui_toolbars }
1048 // Ensure that a file is read only once (prevents include loops)
1049 static std::list<string> uifiles;
1050 std::list<string>::const_iterator it = uifiles.begin();
1051 std::list<string>::const_iterator end = uifiles.end();
1052 it = std::find(it, end, name);
1054 lyxerr[Debug::INIT] << "UI file '" << name
1055 << "' has been read already. "
1056 << "Is this an include loop?"
1061 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1063 string const ui_path = libFileSearch("ui", name, "ui");
1065 if (ui_path.empty()) {
1066 lyxerr[Debug::INIT] << "Could not find " << name << endl;
1067 showFileError(name);
1070 uifiles.push_back(name);
1072 lyxerr[Debug::INIT] << "Found " << name
1073 << " in " << ui_path << endl;
1074 LyXLex lex(uitags, ui_last - 1);
1075 lex.setFile(ui_path);
1077 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1081 if (lyxerr.debugging(Debug::PARSER))
1082 lex.printTable(lyxerr);
1084 while (lex.isOK()) {
1085 switch (lex.lex()) {
1088 string const file = lex.getString();
1089 if (!readUIFile(file))
1094 menubackend.read(lex);
1098 toolbarbackend.read(lex);
1102 toolbarbackend.readToolbars(lex);
1106 if (!rtrim(lex.getString()).empty())
1107 lex.printError("LyX::ReadUIFile: "
1108 "Unknown menu tag: `$$Token'");
1116 // Read the languages file `name'
1117 bool LyX::readLanguagesFile(string const & name)
1119 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1121 string const lang_path = libFileSearch(string(), name);
1122 if (lang_path.empty()) {
1123 showFileError(name);
1126 languages.read(lang_path);
1131 // Read the encodings file `name'
1132 bool LyX::readEncodingsFile(string const & name)
1134 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1136 string const enc_path = libFileSearch(string(), name);
1137 if (enc_path.empty()) {
1138 showFileError(name);
1141 encodings.read(enc_path);
1150 /// return the the number of arguments consumed
1151 typedef boost::function<int(string const &, string const &)> cmd_helper;
1153 int parse_dbg(string const & arg, string const &)
1156 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1157 Debug::showTags(lyxerr);
1160 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1162 lyxerr.level(Debug::value(arg));
1163 Debug::showLevel(lyxerr, lyxerr.level());
1168 int parse_help(string const &, string const &)
1171 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1172 "Command line switches (case sensitive):\n"
1173 "\t-help summarize LyX usage\n"
1174 "\t-userdir dir set user directory to dir\n"
1175 "\t-sysdir dir set system directory to dir\n"
1176 "\t-geometry WxH+X+Y set geometry of the main window\n"
1177 "\t-dbg feature[,feature]...\n"
1178 " select the features to debug.\n"
1179 " Type `lyx -dbg' to see the list of features\n"
1180 "\t-x [--execute] command\n"
1181 " where command is a lyx command.\n"
1182 "\t-e [--export] fmt\n"
1183 " where fmt is the export format of choice.\n"
1184 "\t-i [--import] fmt file.xxx\n"
1185 " where fmt is the import format of choice\n"
1186 " and file.xxx is the file to be imported.\n"
1187 "\t-version summarize version and build info\n"
1188 "Check the LyX man page for more details.")) << endl;
1193 int parse_version(string const &, string const &)
1195 lyxerr << "LyX " << lyx_version
1196 << " (" << lyx_release_date << ")" << endl;
1197 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1199 lyxerr << lyx_version_info << endl;
1204 int parse_sysdir(string const & arg, string const &)
1207 lyxerr << to_utf8(_("Missing directory for -sysdir switch")) << endl;
1210 cl_system_support = arg;
1214 int parse_userdir(string const & arg, string const &)
1217 lyxerr << to_utf8(_("Missing directory for -userdir switch")) << endl;
1220 cl_user_support = arg;
1224 int parse_execute(string const & arg, string const &)
1227 lyxerr << to_utf8(_("Missing command string after --execute switch")) << endl;
1234 int parse_export(string const & type, string const &)
1237 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1238 "--export switch")) << endl;
1241 batch = "buffer-export " + type;
1246 int parse_import(string const & type, string const & file)
1249 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1250 "--import switch")) << endl;
1254 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1258 batch = "buffer-import " + type + ' ' + file;
1265 void LyX::easyParse(int & argc, char * argv[])
1267 std::map<string, cmd_helper> cmdmap;
1269 cmdmap["-dbg"] = parse_dbg;
1270 cmdmap["-help"] = parse_help;
1271 cmdmap["--help"] = parse_help;
1272 cmdmap["-version"] = parse_version;
1273 cmdmap["--version"] = parse_version;
1274 cmdmap["-sysdir"] = parse_sysdir;
1275 cmdmap["-userdir"] = parse_userdir;
1276 cmdmap["-x"] = parse_execute;
1277 cmdmap["--execute"] = parse_execute;
1278 cmdmap["-e"] = parse_export;
1279 cmdmap["--export"] = parse_export;
1280 cmdmap["-i"] = parse_import;
1281 cmdmap["--import"] = parse_import;
1283 for (int i = 1; i < argc; ++i) {
1284 std::map<string, cmd_helper>::const_iterator it
1285 = cmdmap.find(argv[i]);
1287 // check for X11 -geometry option
1288 if (support::compare(argv[i], "-geometry") == 0)
1289 geometryOption_ = true;
1291 // don't complain if not found - may be parsed later
1292 if (it == cmdmap.end())
1295 string arg((i + 1 < argc) ? argv[i + 1] : "");
1296 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1298 int const remove = 1 + it->second(arg, arg2);
1300 // Now, remove used arguments by shifting
1301 // the following ones remove places down.
1303 for (int j = i; j < argc; ++j)
1304 argv[j] = argv[j + remove];
1308 batch_command = batch;
1312 FuncStatus getStatus(FuncRequest const & action)
1314 return LyX::ref().lyxFunc().getStatus(action);
1318 void dispatch(FuncRequest const & action)
1320 LyX::ref().lyxFunc().dispatch(action);
1324 BufferList & theBufferList()
1326 return LyX::ref().bufferList();
1330 LyXFunc & theLyXFunc()
1332 return LyX::ref().lyxFunc();
1336 LyXServer & theLyXServer()
1338 // FIXME: this should not be use_gui dependent
1339 BOOST_ASSERT(use_gui);
1340 return LyX::ref().server();
1344 LyXServerSocket & theLyXServerSocket()
1346 // FIXME: this should not be use_gui dependent
1347 BOOST_ASSERT(use_gui);
1348 return LyX::ref().socket();
1352 kb_keymap & theTopLevelKeymap()
1354 BOOST_ASSERT(use_gui);
1355 return LyX::ref().topLevelKeymap();
1359 IconvProcessor & utf8ToUcs4()
1361 return LyX::ref().iconvProcessor();