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::FileName;
78 using support::fileSearch;
79 using support::getEnv;
80 using support::i18nLibFileSearch;
81 using support::libFileSearch;
82 using support::package;
83 using support::prependEnvPath;
85 using support::Systemcall;
87 namespace Alert = frontend::Alert;
88 namespace os = support::os;
89 namespace fs = boost::filesystem;
96 #ifndef CXX_GLOBAL_CSTD
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;
117 std::string geometryArg;
119 LyX * singleton_ = 0;
121 void showFileError(string const & error)
123 Alert::warning(_("Could not read configuration file"),
124 bformat(_("Error while reading the configuration file\n%1$s.\n"
125 "Please check your installation."), from_utf8(error)));
129 void reconfigureUserLyXDir()
131 string const configure_command = package().configure_command();
133 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
134 support::Path p(package().user_support());
136 one.startscript(Systemcall::Wait, configure_command);
137 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
143 /// The main application class private implementation.
144 struct LyX::Singletons
146 Singletons(): iconv(ucs4_codeset, "UTF-8")
149 /// our function handler
152 BufferList buffer_list_;
154 boost::scoped_ptr<kb_keymap> toplevel_keymap_;
156 boost::scoped_ptr<LyXServer> lyx_server_;
158 boost::scoped_ptr<LyXServerSocket> lyx_socket_;
160 boost::scoped_ptr<frontend::Application> application_;
161 /// lyx session, containing lastfiles, lastfilepos, and lastopened
162 boost::scoped_ptr<Session> session_;
165 IconvProcessor iconv;
169 frontend::Application * theApp()
172 return &singleton_->application();
185 BOOST_ASSERT(singleton_);
190 LyX const & LyX::cref()
192 BOOST_ASSERT(singleton_);
201 pimpl_.reset(new Singletons);
206 BufferList & LyX::bufferList()
208 return pimpl_->buffer_list_;
212 BufferList const & LyX::bufferList() const
214 return pimpl_->buffer_list_;
218 Session & LyX::session()
220 BOOST_ASSERT(pimpl_->session_.get());
221 return *pimpl_->session_.get();
225 Session const & LyX::session() const
227 BOOST_ASSERT(pimpl_->session_.get());
228 return *pimpl_->session_.get();
232 LyXFunc & LyX::lyxFunc()
234 return pimpl_->lyxfunc_;
238 LyXFunc const & LyX::lyxFunc() const
240 return pimpl_->lyxfunc_;
244 LyXServer & LyX::server()
246 BOOST_ASSERT(pimpl_->lyx_server_.get());
247 return *pimpl_->lyx_server_.get();
251 LyXServer const & LyX::server() const
253 BOOST_ASSERT(pimpl_->lyx_server_.get());
254 return *pimpl_->lyx_server_.get();
258 LyXServerSocket & LyX::socket()
260 BOOST_ASSERT(pimpl_->lyx_socket_.get());
261 return *pimpl_->lyx_socket_.get();
265 LyXServerSocket const & LyX::socket() const
267 BOOST_ASSERT(pimpl_->lyx_socket_.get());
268 return *pimpl_->lyx_socket_.get();
272 frontend::Application & LyX::application()
274 BOOST_ASSERT(pimpl_->application_.get());
275 return *pimpl_->application_.get();
279 frontend::Application const & LyX::application() const
281 BOOST_ASSERT(pimpl_->application_.get());
282 return *pimpl_->application_.get();
286 kb_keymap & LyX::topLevelKeymap()
288 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
289 return *pimpl_->toplevel_keymap_.get();
293 IconvProcessor & LyX::iconvProcessor()
295 return pimpl_->iconv;
299 kb_keymap const & LyX::topLevelKeymap() const
301 BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
302 return *pimpl_->toplevel_keymap_.get();
306 Buffer const * const LyX::updateInset(InsetBase const * inset) const
311 Buffer const * buffer_ptr = 0;
312 vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
313 vector<int>::const_iterator it = view_ids.begin();
314 vector<int>::const_iterator const end = view_ids.end();
315 for (; it != end; ++it) {
317 pimpl_->application_->gui().view(*it).updateInset(inset);
325 int LyX::exec(int & argc, char * argv[])
327 // Here we need to parse the command line. At least
328 // we need to parse for "-dbg" and "-help"
329 easyParse(argc, argv);
331 support::init_package(argv[0], cl_system_support, cl_user_support,
332 support::top_build_dir_is_one_level_up);
334 vector<FileName> files;
337 // FIXME: create a ConsoleApplication
338 int exit_status = loadFiles(argc, argv, files);
344 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
349 BufferList::iterator begin = pimpl_->buffer_list_.begin();
350 BufferList::iterator end = pimpl_->buffer_list_.end();
352 bool final_success = false;
353 for (BufferList::iterator I = begin; I != end; ++I) {
355 bool success = false;
356 buf->dispatch(batch_command, &success);
357 final_success |= success;
360 return !final_success;
363 // Force adding of font path _before_ Application is initialized
364 support::addFontResources();
366 // Let the frontend parse and remove all arguments that it knows
367 pimpl_->application_.reset(createApplication(argc, argv));
371 // Parse and remove all known arguments in the LyX singleton
372 // Give an error for all remaining ones.
373 int exit_status = loadFiles(argc, argv, files);
375 // Kill the application object before exiting.
376 pimpl_->application_.reset();
382 restoreGuiSession(files);
383 // Start the real execution loop.
386 /* Create a CoreApplication class that will provide the main event loop
387 * and the socket callback registering. With Qt4, only QtCore
388 * library would be needed.
389 * When this is done, a server_mode could be created and the following two
390 * line would be moved out from here.
392 pimpl_->lyx_server_.reset(new LyXServer(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
393 pimpl_->lyx_socket_.reset(new LyXServerSocket(&pimpl_->lyxfunc_,
394 support::os::internal_path(package().temp_dir() + "/lyxsocket")));
396 exit_status = pimpl_->application_->exec();
400 // Restore original font resources after Application is destroyed.
401 support::restoreFontResources();
407 void LyX::prepareExit()
409 // Set a flag that we do quitting from the program,
410 // so no refreshes are necessary.
413 // close buffers first
414 pimpl_->buffer_list_.closeAll();
416 // do any other cleanup procedures now
417 lyxerr[Debug::INFO] << "Deleting tmp dir " << package().temp_dir() << endl;
419 // Prevent the deletion of /tmp if LyX was called with invalid
420 // arguments. Does not work on windows.
421 // FIXME: Fix the real bug instead.
422 if (package().temp_dir() == "/tmp") {
423 lyxerr << "Not deleting /tmp." << endl;
427 if (!destroyDir(package().temp_dir())) {
428 docstring const msg =
429 bformat(_("Unable to remove the temporary directory %1$s"),
430 from_utf8(package().temp_dir()));
431 Alert::warning(_("Unable to remove temporary directory"), msg);
435 if (pimpl_->session_)
436 pimpl_->session_->writeFile();
437 pimpl_->session_.reset();
438 pimpl_->lyx_server_.reset();
439 pimpl_->lyx_socket_.reset();
442 // Kill the application object before exiting. This avoids crashes
443 // when exiting on Linux.
444 if (pimpl_->application_)
445 pimpl_->application_.reset();
449 void LyX::earlyExit(int status)
451 BOOST_ASSERT(pimpl_->application_.get());
452 // LyX::pimpl_::application_ is not initialised at this
453 // point so it's safe to just exit after some cleanup.
459 int LyX::loadFiles(int & argc, char * argv[],
460 vector<FileName> & files)
462 // check for any spurious extra arguments
463 // other than documents
464 for (int argi = 1; argi < argc ; ++argi) {
465 if (argv[argi][0] == '-') {
467 bformat(_("Wrong command line option `%1$s'. Exiting."),
468 from_utf8(argv[argi]))) << endl;
473 // Initialization of LyX (reads lyxrc and more)
474 lyxerr[Debug::INIT] << "Initializing LyX::init..." << endl;
475 bool success = init();
476 lyxerr[Debug::INIT] << "Initializing LyX::init...done" << endl;
480 for (int argi = argc - 1; argi >= 1; --argi) {
481 // check for any remaining extra arguments other than
482 // document file names. These will be passed out to the
484 if (argv[argi][0] == '-')
486 // get absolute path of file and add ".lyx" to
487 // the filename if necessary
488 files.push_back(fileSearch(string(), os::internal_path(argv[argi]), "lyx"));
492 files.push_back(i18nLibFileSearch("examples", "splash.lyx"));
494 Buffer * last_loaded = 0;
496 vector<FileName>::const_iterator it = files.begin();
497 vector<FileName>::const_iterator end = files.end();
499 for (; it != end; ++it) {
501 Buffer * const b = newFile(it->absFilename(), string(), true);
505 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
506 if (loadLyXFile(buf, *it)) {
508 ErrorList const & el = buf->errorList("Parse");
510 for_each(el.begin(), el.end(),
511 boost::bind(&LyX::printError, this, _1));
514 pimpl_->buffer_list_.release(buf);
518 files.clear(); // the files are already loaded
524 void LyX::execBatchCommands()
526 // Execute batch commands if available
527 if (batch_command.empty())
530 lyxerr[Debug::INIT] << "About to handle -x '"
531 << batch_command << '\'' << endl;
533 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(batch_command));
537 void LyX::restoreGuiSession(vector<FileName> const & files)
539 LyXView * view = newLyXView();
542 for_each(files.begin(), files.end(),
543 bind(&LyXView::loadLyXFile, view, _1, true));
545 // if a file is specified, I assume that user wants to edit *that* file
546 if (files.empty() && lyxrc.load_session) {
547 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
548 // do not add to the lastfile list since these files are restored from
549 // last seesion, and should be already there (regular files), or should
550 // not be added at all (help files).
551 for_each(lastopened.begin(), lastopened.end(),
552 bind(&LyXView::loadLyXFile, view, _1, false));
554 // clear this list to save a few bytes of RAM
555 pimpl_->session_->lastOpened().clear();
559 LyXView * LyX::newLyXView()
564 // determine windows size and position, from lyxrc and/or session
566 unsigned int width = 690;
567 unsigned int height = 510;
568 // default icon size, will be overwritten by stored session value
569 unsigned int iconSizeXY = 0;
570 bool maximize = false;
572 if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
573 width = lyxrc.geometry_width;
574 height = lyxrc.geometry_height;
576 // if lyxrc returns (0,0), then use session info
578 string val = session().sessionInfo().load("WindowWidth");
580 width = convert<unsigned int>(val);
581 val = session().sessionInfo().load("WindowHeight");
583 height = convert<unsigned int>(val);
584 if (session().sessionInfo().load("WindowIsMaximized") == "yes")
586 val = session().sessionInfo().load("IconSizeXY");
588 iconSizeXY = convert<unsigned int>(val);
591 // if user wants to restore window position
594 if (lyxrc.geometry_xysaved) {
595 string val = session().sessionInfo().load("WindowPosX");
597 posx = convert<int>(val);
598 val = session().sessionInfo().load("WindowPosY");
600 posy = convert<int>(val);
603 if (!geometryArg.empty())
609 // create the main window
610 LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximize, iconSizeXY, geometryArg);
618 The SIGHUP signal does not exist on Windows and does not need to be handled.
620 Windows handles SIGFPE and SIGSEGV signals as expected.
622 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
623 cause a new thread to be spawned. This may well result in unexpected
624 behaviour by the single-threaded LyX.
626 SIGTERM signals will come only from another process actually sending
627 that signal using 'raise' in Windows' POSIX compatability layer. It will
628 not come from the general "terminate process" methods that everyone
629 actually uses (and which can't be trapped). Killing an app 'politely' on
630 Windows involves first sending a WM_CLOSE message, something that is
631 caught already by the Qt frontend.
633 For more information see:
635 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
636 ...signals are mostly useless on Windows for a variety of reasons that are
639 'UNIX Application Migration Guide, Chapter 9'
640 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
642 'How To Terminate an Application "Cleanly" in Win32'
643 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
647 static void error_handler(int err_sig)
649 // Throw away any signals other than the first one received.
650 static sig_atomic_t handling_error = false;
653 handling_error = true;
655 // We have received a signal indicating a fatal error, so
656 // try and save the data ASAP.
657 LyX::cref().emergencyCleanup();
659 // These lyxerr calls may or may not work:
661 // Signals are asynchronous, so the main program may be in a very
662 // fragile state when a signal is processed and thus while a signal
663 // handler function executes.
664 // In general, therefore, we should avoid performing any
665 // I/O operations or calling most library and system functions from
668 // This shouldn't matter here, however, as we've already invoked
673 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
677 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
680 lyxerr << "\nlyx: SIGSEGV signal caught\n"
681 "Sorry, you have found a bug in LyX. "
682 "Please read the bug-reporting instructions "
683 "in Help->Introduction and send us a bug report, "
684 "if necessary. Thanks !\nBye." << endl;
692 // Deinstall the signal handlers
694 signal(SIGHUP, SIG_DFL);
696 signal(SIGINT, SIG_DFL);
697 signal(SIGFPE, SIG_DFL);
698 signal(SIGSEGV, SIG_DFL);
699 signal(SIGTERM, SIG_DFL);
702 if (err_sig == SIGSEGV ||
703 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
705 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
714 void LyX::printError(ErrorItem const & ei)
716 docstring tmp = _("LyX: ") + ei.error + char_type(':')
718 std::cerr << to_utf8(tmp) << std::endl;
722 void LyX::initGuiFont()
724 if (lyxrc.roman_font_name.empty())
725 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
727 if (lyxrc.sans_font_name.empty())
728 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
730 if (lyxrc.typewriter_font_name.empty())
731 lyxrc.typewriter_font_name
732 = pimpl_->application_->typewriterFontName();
739 signal(SIGHUP, error_handler);
741 signal(SIGFPE, error_handler);
742 signal(SIGSEGV, error_handler);
743 signal(SIGINT, error_handler);
744 signal(SIGTERM, error_handler);
745 // SIGPIPE can be safely ignored.
747 lyxrc.tempdir_path = package().temp_dir();
748 lyxrc.document_path = package().document_dir();
750 if (lyxrc.template_path.empty()) {
751 lyxrc.template_path = addPath(package().system_support(),
756 // Read configuration files
759 // This one may have been distributed along with LyX.
760 if (!readRcFile("lyxrc.dist"))
763 // Set the PATH correctly.
764 #if !defined (USE_POSIX_PACKAGING)
765 // Add the directory containing the LyX executable to the path
766 // so that LyX can find things like tex2lyx.
767 if (package().build_support().empty())
768 prependEnvPath("PATH", package().binary_dir());
770 if (!lyxrc.path_prefix.empty())
771 prependEnvPath("PATH", lyxrc.path_prefix);
773 // Check that user LyX directory is ok.
774 if (queryUserLyXDir(package().explicit_user_support()))
775 reconfigureUserLyXDir();
777 // no need for a splash when there is no GUI
782 // This one is generated in user_support directory by lib/configure.py.
783 if (!readRcFile("lyxrc.defaults"))
786 // Query the OS to know what formats are viewed natively
787 formats.setAutoOpen();
789 // Read lyxrc.dist again to be able to override viewer auto-detection.
790 readRcFile("lyxrc.dist");
792 system_lyxrc = lyxrc;
793 system_formats = formats;
794 system_converters = converters;
795 system_movers = movers;
796 system_lcolor = lcolor;
798 // This one is edited through the preferences dialog.
799 if (!readRcFile("preferences"))
802 if (!readEncodingsFile("encodings"))
804 if (!readLanguagesFile("languages"))
808 lyxerr[Debug::INIT] << "Reading layouts..." << endl;
814 pimpl_->toplevel_keymap_.reset(new kb_keymap);
815 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
816 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
818 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
821 if (!readUIFile(lyxrc.ui_file))
825 if (lyxerr.debugging(Debug::LYXRC))
828 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
829 if (!lyxrc.path_prefix.empty())
830 prependEnvPath("PATH", lyxrc.path_prefix);
832 if (fs::exists(lyxrc.document_path) &&
833 fs::is_directory(lyxrc.document_path))
834 package().document_dir() = lyxrc.document_path;
836 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path)).absFilename();
837 if (package().temp_dir().empty()) {
838 Alert::error(_("Could not create temporary directory"),
839 bformat(_("Could not create a temporary directory in\n"
840 "%1$s. Make sure that this\n"
841 "path exists and is writable and try again."),
842 from_utf8(lyxrc.tempdir_path)));
843 // createLyXTmpDir() tries sufficiently hard to create a
844 // usable temp dir, so the probability to come here is
845 // close to zero. We therefore don't try to overcome this
846 // problem with e.g. asking the user for a new path and
847 // trying again but simply exit.
851 if (lyxerr.debugging(Debug::INIT)) {
852 lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl;
855 lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl;
856 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
858 // This must happen after package initialization and after lyxrc is
859 // read, therefore it can't be done by a static object.
860 ConverterCache::init();
866 void LyX::defaultKeyBindings(kb_keymap * kbmap)
868 kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
869 kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
870 kbmap->bind("Up", FuncRequest(LFUN_UP));
871 kbmap->bind("Down", FuncRequest(LFUN_DOWN));
873 kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
874 kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
875 kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
876 kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
878 kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
879 kbmap->bind("End", FuncRequest(LFUN_LINE_END));
880 kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
881 kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
883 kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
884 //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
886 kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
887 kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
889 // kbmap->bindings to enable the use of the numeric keypad
891 //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
892 //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
893 kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
894 //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
895 //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
896 //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
897 //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
898 //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
899 //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
900 //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
901 //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
902 //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
903 //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
904 //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
905 //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
906 //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
907 kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
908 kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
909 kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
910 kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
911 kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
912 kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
913 kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
914 kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
918 void LyX::emergencyCleanup() const
920 // what to do about tmpfiles is non-obvious. we would
921 // like to delete any we find, but our lyxdir might
922 // contain documents etc. which might be helpful on
925 pimpl_->buffer_list_.emergencyWriteAll();
927 if (pimpl_->lyx_server_)
928 pimpl_->lyx_server_->emergencyCleanup();
929 pimpl_->lyx_server_.reset();
930 pimpl_->lyx_socket_.reset();
935 void LyX::deadKeyBindings(kb_keymap * kbmap)
937 // bindKeyings for transparent handling of deadkeys
938 // The keysyms are gotten from XFree86 X11R6
939 kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
940 kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
941 kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
942 kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
943 kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
944 kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
945 kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
946 kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
947 kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
948 kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
949 // nothing with this name
950 // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
951 kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
952 kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
953 // nothing with this name either...
954 //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
955 kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
956 kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
957 kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
963 // return true if file does not exist or is older than configure.py.
964 bool needsUpdate(string const & file)
966 static string const configure_script =
967 addName(package().system_support(), "configure.py");
968 string const absfile =
969 addName(package().user_support(), file);
971 return (! fs::exists(absfile))
972 || (fs::last_write_time(configure_script)
973 > fs::last_write_time(absfile));
979 bool LyX::queryUserLyXDir(bool explicit_userdir)
981 // Does user directory exist?
982 if (fs::exists(package().user_support()) &&
983 fs::is_directory(package().user_support())) {
986 return needsUpdate("lyxrc.defaults")
987 || needsUpdate("textclass.lst")
988 || needsUpdate("packages.lst");
991 first_start = !explicit_userdir;
993 // If the user specified explicitly a directory, ask whether
994 // to create it. If the user says "no", then exit.
995 if (explicit_userdir &&
997 _("Missing user LyX directory"),
998 bformat(_("You have specified a non-existent user "
999 "LyX directory, %1$s.\n"
1000 "It is needed to keep your own configuration."),
1001 from_utf8(package().user_support())),
1003 _("&Create directory"),
1005 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1006 earlyExit(EXIT_FAILURE);
1009 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1010 from_utf8(package().user_support())))
1013 if (!createDirectory(package().user_support(), 0755)) {
1014 // Failed, so let's exit.
1015 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1017 earlyExit(EXIT_FAILURE);
1024 bool LyX::readRcFile(string const & name)
1026 lyxerr[Debug::INIT] << "About to read " << name << "... ";
1028 FileName const lyxrc_path = libFileSearch(string(), name);
1029 if (!lyxrc_path.empty()) {
1031 lyxerr[Debug::INIT] << "Found in " << lyxrc_path << endl;
1033 if (lyxrc.read(lyxrc_path) < 0) {
1034 showFileError(name);
1038 lyxerr[Debug::INIT] << "Not found." << lyxrc_path << endl;
1044 // Read the ui file `name'
1045 bool LyX::readUIFile(string const & name)
1055 struct keyword_item uitags[ui_last - 1] = {
1056 { "include", ui_include },
1057 { "menuset", ui_menuset },
1058 { "toolbar", ui_toolbar },
1059 { "toolbars", ui_toolbars }
1062 // Ensure that a file is read only once (prevents include loops)
1063 static std::list<string> uifiles;
1064 std::list<string>::const_iterator it = uifiles.begin();
1065 std::list<string>::const_iterator end = uifiles.end();
1066 it = std::find(it, end, name);
1068 lyxerr[Debug::INIT] << "UI file '" << name
1069 << "' has been read already. "
1070 << "Is this an include loop?"
1075 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1077 FileName const ui_path = libFileSearch("ui", name, "ui");
1079 if (ui_path.empty()) {
1080 lyxerr[Debug::INIT] << "Could not find " << name << endl;
1081 showFileError(name);
1084 uifiles.push_back(name);
1086 lyxerr[Debug::INIT] << "Found " << name
1087 << " in " << ui_path << endl;
1088 LyXLex lex(uitags, ui_last - 1);
1089 lex.setFile(ui_path);
1091 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1095 if (lyxerr.debugging(Debug::PARSER))
1096 lex.printTable(lyxerr);
1098 while (lex.isOK()) {
1099 switch (lex.lex()) {
1102 string const file = lex.getString();
1103 if (!readUIFile(file))
1108 menubackend.read(lex);
1112 toolbarbackend.read(lex);
1116 toolbarbackend.readToolbars(lex);
1120 if (!rtrim(lex.getString()).empty())
1121 lex.printError("LyX::ReadUIFile: "
1122 "Unknown menu tag: `$$Token'");
1130 // Read the languages file `name'
1131 bool LyX::readLanguagesFile(string const & name)
1133 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1135 FileName const lang_path = libFileSearch(string(), name);
1136 if (lang_path.empty()) {
1137 showFileError(name);
1140 languages.read(lang_path);
1145 // Read the encodings file `name'
1146 bool LyX::readEncodingsFile(string const & name)
1148 lyxerr[Debug::INIT] << "About to read " << name << "..." << endl;
1150 FileName const enc_path = libFileSearch(string(), name);
1151 if (enc_path.empty()) {
1152 showFileError(name);
1155 encodings.read(enc_path);
1164 /// return the the number of arguments consumed
1165 typedef boost::function<int(string const &, string const &)> cmd_helper;
1167 int parse_dbg(string const & arg, string const &)
1170 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1171 Debug::showTags(lyxerr);
1174 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1176 lyxerr.level(Debug::value(arg));
1177 Debug::showLevel(lyxerr, lyxerr.level());
1182 int parse_help(string const &, string const &)
1185 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1186 "Command line switches (case sensitive):\n"
1187 "\t-help summarize LyX usage\n"
1188 "\t-userdir dir set user directory to dir\n"
1189 "\t-sysdir dir set system directory to dir\n"
1190 "\t-geometry WxH+X+Y set geometry of the main window\n"
1191 "\t-dbg feature[,feature]...\n"
1192 " select the features to debug.\n"
1193 " Type `lyx -dbg' to see the list of features\n"
1194 "\t-x [--execute] command\n"
1195 " where command is a lyx command.\n"
1196 "\t-e [--export] fmt\n"
1197 " where fmt is the export format of choice.\n"
1198 "\t-i [--import] fmt file.xxx\n"
1199 " where fmt is the import format of choice\n"
1200 " and file.xxx is the file to be imported.\n"
1201 "\t-version summarize version and build info\n"
1202 "Check the LyX man page for more details.")) << endl;
1207 int parse_version(string const &, string const &)
1209 lyxerr << "LyX " << lyx_version
1210 << " (" << lyx_release_date << ")" << endl;
1211 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1213 lyxerr << lyx_version_info << endl;
1218 int parse_sysdir(string const & arg, string const &)
1221 lyxerr << to_utf8(_("Missing directory for -sysdir switch")) << endl;
1224 cl_system_support = arg;
1228 int parse_userdir(string const & arg, string const &)
1231 lyxerr << to_utf8(_("Missing directory for -userdir switch")) << endl;
1234 cl_user_support = arg;
1238 int parse_execute(string const & arg, string const &)
1241 lyxerr << to_utf8(_("Missing command string after --execute switch")) << endl;
1248 int parse_export(string const & type, string const &)
1251 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1252 "--export switch")) << endl;
1255 batch = "buffer-export " + type;
1260 int parse_import(string const & type, string const & file)
1263 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1264 "--import switch")) << endl;
1268 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1272 batch = "buffer-import " + type + ' ' + file;
1276 int parse_geometry(string const & arg1, string const &)
1279 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1280 // remove also the arg
1283 // don't remove "-geometry"
1292 void LyX::easyParse(int & argc, char * argv[])
1294 std::map<string, cmd_helper> cmdmap;
1296 cmdmap["-dbg"] = parse_dbg;
1297 cmdmap["-help"] = parse_help;
1298 cmdmap["--help"] = parse_help;
1299 cmdmap["-version"] = parse_version;
1300 cmdmap["--version"] = parse_version;
1301 cmdmap["-sysdir"] = parse_sysdir;
1302 cmdmap["-userdir"] = parse_userdir;
1303 cmdmap["-x"] = parse_execute;
1304 cmdmap["--execute"] = parse_execute;
1305 cmdmap["-e"] = parse_export;
1306 cmdmap["--export"] = parse_export;
1307 cmdmap["-i"] = parse_import;
1308 cmdmap["--import"] = parse_import;
1309 cmdmap["-geometry"] = parse_geometry;
1311 for (int i = 1; i < argc; ++i) {
1312 std::map<string, cmd_helper>::const_iterator it
1313 = cmdmap.find(argv[i]);
1315 // don't complain if not found - may be parsed later
1316 if (it == cmdmap.end())
1319 string arg((i + 1 < argc) ? argv[i + 1] : "");
1320 string arg2((i + 2 < argc) ? argv[i + 2] : "");
1322 int const remove = 1 + it->second(arg, arg2);
1324 // Now, remove used arguments by shifting
1325 // the following ones remove places down.
1328 for (int j = i; j < argc; ++j)
1329 argv[j] = argv[j + remove];
1334 batch_command = batch;
1338 FuncStatus getStatus(FuncRequest const & action)
1340 return LyX::ref().lyxFunc().getStatus(action);
1344 void dispatch(FuncRequest const & action)
1346 LyX::ref().lyxFunc().dispatch(action);
1350 BufferList & theBufferList()
1352 return LyX::ref().bufferList();
1356 LyXFunc & theLyXFunc()
1358 return LyX::ref().lyxFunc();
1362 LyXServer & theLyXServer()
1364 // FIXME: this should not be use_gui dependent
1365 BOOST_ASSERT(use_gui);
1366 return LyX::ref().server();
1370 LyXServerSocket & theLyXServerSocket()
1372 // FIXME: this should not be use_gui dependent
1373 BOOST_ASSERT(use_gui);
1374 return LyX::ref().socket();
1378 kb_keymap & theTopLevelKeymap()
1380 BOOST_ASSERT(use_gui);
1381 return LyX::ref().topLevelKeymap();
1385 IconvProcessor & utf8ToUcs4()
1387 return LyX::ref().iconvProcessor();