]> git.lyx.org Git - lyx.git/blob - src/LyX.cpp
Add format hint for command line export
[lyx.git] / src / LyX.cpp
1 /**
2  * \file LyX.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braunstein
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author John Levon
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16 #include <version.h>
17
18 #include "LyX.h"
19
20 #include "Color.h"
21 #include "ConverterCache.h"
22 #include "Buffer.h"
23 #include "buffer_funcs.h"
24 #include "BufferList.h"
25 #include "Converter.h"
26 #include "CutAndPaste.h"
27 #include "debug.h"
28 #include "Encoding.h"
29 #include "ErrorList.h"
30 #include "Format.h"
31 #include "gettext.h"
32 #include "KeyMap.h"
33 #include "CmdDef.h"
34 #include "Language.h"
35 #include "Session.h"
36 #include "LyXAction.h"
37 #include "LyXFunc.h"
38 #include "Lexer.h"
39 #include "LyXRC.h"
40 #include "ModuleList.h"
41 #include "Server.h"
42 #include "ServerSocket.h"
43 #include "TextClassList.h"
44 #include "MenuBackend.h"
45 #include "Messages.h"
46 #include "Mover.h"
47 #include "ToolbarBackend.h"
48
49 #include "frontends/alert.h"
50 #include "frontends/Application.h"
51 #include "frontends/Dialogs.h"
52 #include "frontends/Gui.h"
53 #include "frontends/LyXView.h"
54
55 #include "support/environment.h"
56 #include "support/filetools.h"
57 #include "support/lstrings.h"
58 #include "support/lyxlib.h"
59 #include "support/ExceptionMessage.h"
60 #include "support/os.h"
61 #include "support/Package.h"
62 #include "support/Path.h"
63 #include "support/Systemcall.h"
64
65 #include <boost/bind.hpp>
66 #include <boost/scoped_ptr.hpp>
67
68 #include <algorithm>
69 #include <iostream>
70 #include <csignal>
71 #include <map>
72 #include <string>
73 #include <vector>
74
75 using std::endl;
76 using std::for_each;
77 using std::map;
78 using std::make_pair;
79 using std::string;
80 using std::vector;
81
82 #ifndef CXX_GLOBAL_CSTD
83 using std::exit;
84 using std::signal;
85 using std::system;
86 #endif
87
88 namespace lyx {
89
90 using support::addName;
91 using support::addPath;
92 using support::bformat;
93 using support::changeExtension;
94 using support::createLyXTmpDir;
95 using support::FileName;
96 using support::fileSearch;
97 using support::getEnv;
98 using support::i18nLibFileSearch;
99 using support::libFileSearch;
100 using support::package;
101 using support::prependEnvPath;
102 using support::rtrim;
103 using support::Systemcall;
104 using frontend::LyXView;
105
106 namespace Alert = frontend::Alert;
107 namespace os = support::os;
108
109
110
111 // Are we using the GUI at all?  We default to true and this is changed
112 // to false when the export feature is used.
113
114 bool use_gui = true;
115
116 bool quitting;  // flag, that we are quitting the program
117
118 namespace {
119
120 // Filled with the command line arguments "foo" of "-sysdir foo" or
121 // "-userdir foo".
122 string cl_system_support;
123 string cl_user_support;
124
125 std::string geometryArg;
126
127 LyX * singleton_ = 0;
128
129 void showFileError(string const & error)
130 {
131         Alert::warning(_("Could not read configuration file"),
132                        bformat(_("Error while reading the configuration file\n%1$s.\n"
133                            "Please check your installation."), from_utf8(error)));
134 }
135
136
137 void reconfigureUserLyXDir()
138 {
139         string const configure_command = package().configure_command();
140
141         lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
142         support::PathChanger p(package().user_support());
143         Systemcall one;
144         one.startscript(Systemcall::Wait, configure_command);
145         lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
146 }
147
148 } // namespace anon
149
150
151 /// The main application class private implementation.
152 struct LyX::Impl
153 {
154         Impl()
155         {
156                 // Set the default User Interface language as soon as possible.
157                 // The language used will be derived from the environment
158                 // variables.
159                 messages_["GUI"] = Messages();
160         }
161         /// our function handler
162         LyXFunc lyxfunc_;
163         ///
164         BufferList buffer_list_;
165         ///
166         boost::scoped_ptr<KeyMap> toplevel_keymap_;
167         ///
168         boost::scoped_ptr<CmdDef> toplevel_cmddef_;
169         ///
170         boost::scoped_ptr<Server> lyx_server_;
171         ///
172         boost::scoped_ptr<ServerSocket> lyx_socket_;
173         ///
174         boost::scoped_ptr<frontend::Application> application_;
175         /// lyx session, containing lastfiles, lastfilepos, and lastopened
176         boost::scoped_ptr<Session> session_;
177
178         /// Files to load at start.
179         vector<FileName> files_to_load_;
180
181         /// The messages translators.
182         map<string, Messages> messages_;
183
184         /// The file converters.
185         Converters converters_;
186
187         // The system converters copy after reading lyxrc.defaults.
188         Converters system_converters_;
189
190         ///
191         Movers movers_;
192         ///
193         Movers system_movers_;
194
195         /// has this user started lyx for the first time?
196         bool first_start;
197         /// the parsed command line batch command if any
198         std::string batch_command;
199 };
200
201 ///
202 frontend::Application * theApp()
203 {
204         if (singleton_)
205                 return singleton_->pimpl_->application_.get();
206         else
207                 return 0;
208 }
209
210
211 LyX::~LyX()
212 {
213         delete pimpl_;
214 }
215
216
217 LyX & LyX::ref()
218 {
219         BOOST_ASSERT(singleton_);
220         return *singleton_;
221 }
222
223
224 LyX const & LyX::cref()
225 {
226         BOOST_ASSERT(singleton_);
227         return *singleton_;
228 }
229
230
231 LyX::LyX()
232         : first_start(false)
233 {
234         singleton_ = this;
235         pimpl_ = new Impl;
236 }
237
238
239 BufferList & LyX::bufferList()
240 {
241         return pimpl_->buffer_list_;
242 }
243
244
245 BufferList const & LyX::bufferList() const
246 {
247         return pimpl_->buffer_list_;
248 }
249
250
251 Session & LyX::session()
252 {
253         BOOST_ASSERT(pimpl_->session_.get());
254         return *pimpl_->session_.get();
255 }
256
257
258 Session const & LyX::session() const
259 {
260         BOOST_ASSERT(pimpl_->session_.get());
261         return *pimpl_->session_.get();
262 }
263
264
265 LyXFunc & LyX::lyxFunc()
266 {
267         return pimpl_->lyxfunc_;
268 }
269
270
271 LyXFunc const & LyX::lyxFunc() const
272 {
273         return pimpl_->lyxfunc_;
274 }
275
276
277 Server & LyX::server()
278 {
279         BOOST_ASSERT(pimpl_->lyx_server_.get());
280         return *pimpl_->lyx_server_.get();
281 }
282
283
284 Server const & LyX::server() const
285 {
286         BOOST_ASSERT(pimpl_->lyx_server_.get());
287         return *pimpl_->lyx_server_.get();
288 }
289
290
291 ServerSocket & LyX::socket()
292 {
293         BOOST_ASSERT(pimpl_->lyx_socket_.get());
294         return *pimpl_->lyx_socket_.get();
295 }
296
297
298 ServerSocket const & LyX::socket() const
299 {
300         BOOST_ASSERT(pimpl_->lyx_socket_.get());
301         return *pimpl_->lyx_socket_.get();
302 }
303
304
305 frontend::Application & LyX::application()
306 {
307         BOOST_ASSERT(pimpl_->application_.get());
308         return *pimpl_->application_.get();
309 }
310
311
312 frontend::Application const & LyX::application() const
313 {
314         BOOST_ASSERT(pimpl_->application_.get());
315         return *pimpl_->application_.get();
316 }
317
318
319 KeyMap & LyX::topLevelKeymap()
320 {
321         BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
322         return *pimpl_->toplevel_keymap_.get();
323 }
324
325
326 CmdDef & LyX::topLevelCmdDef()
327 {
328         BOOST_ASSERT(pimpl_->toplevel_cmddef_.get());
329         return *pimpl_->toplevel_cmddef_.get();
330 }
331
332
333 Converters & LyX::converters()
334 {
335         return pimpl_->converters_;
336 }
337
338
339 Converters & LyX::systemConverters()
340 {
341         return pimpl_->system_converters_;
342 }
343
344
345 KeyMap const & LyX::topLevelKeymap() const
346 {
347         BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
348         return *pimpl_->toplevel_keymap_.get();
349 }
350
351
352 Messages & LyX::getMessages(std::string const & language)
353 {
354         map<string, Messages>::iterator it = pimpl_->messages_.find(language);
355
356         if (it != pimpl_->messages_.end())
357                 return it->second;
358
359         std::pair<map<string, Messages>::iterator, bool> result =
360                         pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
361
362         BOOST_ASSERT(result.second);
363         return result.first->second;
364 }
365
366
367 Messages & LyX::getGuiMessages()
368 {
369         return pimpl_->messages_["GUI"];
370 }
371
372
373 void LyX::setGuiLanguage(std::string const & language)
374 {
375         pimpl_->messages_["GUI"] = Messages(language);
376 }
377
378
379 Buffer const * LyX::updateInset(Inset const * inset) const
380 {
381         if (quitting || !inset)
382                 return 0;
383
384         Buffer const * buffer_ptr = 0;
385         vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
386         vector<int>::const_iterator it = view_ids.begin();
387         vector<int>::const_iterator const end = view_ids.end();
388         for (; it != end; ++it) {
389                 Buffer const * ptr =
390                         pimpl_->application_->gui().view(*it).updateInset(inset);
391                 if (ptr)
392                         buffer_ptr = ptr;
393         }
394         return buffer_ptr;
395 }
396
397
398 void LyX::hideDialogs(std::string const & name, Inset * inset) const
399 {
400         if (quitting || !use_gui)
401                 return;
402
403         vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
404         vector<int>::const_iterator it = view_ids.begin();
405         vector<int>::const_iterator const end = view_ids.end();
406         for (; it != end; ++it)
407                 pimpl_->application_->gui().view(*it).getDialogs().
408                         hide(name, inset);
409 }
410
411
412 int LyX::exec(int & argc, char * argv[])
413 {
414         // Here we need to parse the command line. At least
415         // we need to parse for "-dbg" and "-help"
416         easyParse(argc, argv);
417
418         try {
419                 support::init_package(to_utf8(from_local8bit(argv[0])),
420                               cl_system_support, cl_user_support,
421                               support::top_build_dir_is_one_level_up);
422         } catch (support::ExceptionMessage const & message) {
423                 if (message.type_ == support::ErrorException) {
424                         Alert::error(message.title_, message.details_);
425                         exit(1);
426                 } else if (message.type_ == support::WarningException) {
427                         Alert::warning(message.title_, message.details_);
428                 }
429         }
430
431         // Reinit the messages machinery in case package() knows
432         // something interesting about the locale directory.
433         Messages::init();
434
435         if (!use_gui) {
436                 // FIXME: create a ConsoleApplication
437                 int exit_status = init(argc, argv);
438                 if (exit_status) {
439                         prepareExit();
440                         return exit_status;
441                 }
442
443                 loadFiles();
444
445                 if (pimpl_->batch_command.empty() || pimpl_->buffer_list_.empty()) {
446                         prepareExit();
447                         return EXIT_SUCCESS;
448                 }
449
450                 BufferList::iterator begin = pimpl_->buffer_list_.begin();
451
452                 bool final_success = false;
453                 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
454                         Buffer * buf = *I;
455                         if (buf != buf->masterBuffer())
456                                 continue;
457                         bool success = false;
458                         buf->dispatch(pimpl_->batch_command, &success);
459                         final_success |= success;
460                 }
461                 prepareExit();
462                 return !final_success;
463         }
464
465         // Let the frontend parse and remove all arguments that it knows
466         pimpl_->application_.reset(createApplication(argc, argv));
467
468         initGuiFont();
469
470         // Parse and remove all known arguments in the LyX singleton
471         // Give an error for all remaining ones.
472         int exit_status = init(argc, argv);
473         if (exit_status) {
474                 // Kill the application object before exiting.
475                 pimpl_->application_.reset();
476                 use_gui = false;
477                 prepareExit();
478                 return exit_status;
479         }
480
481         // FIXME
482         /* Create a CoreApplication class that will provide the main event loop
483         * and the socket callback registering. With Qt4, only QtCore
484         * library would be needed.
485         * When this is done, a server_mode could be created and the following two
486         * line would be moved out from here.
487         */
488         // Note: socket callback must be registered after init(argc, argv)
489         // such that package().temp_dir() is properly initialized.
490         pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
491         pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
492                         FileName(package().temp_dir().absFilename() + "/lyxsocket")));
493
494         // Start the real execution loop.
495         exit_status = pimpl_->application_->exec();
496
497         prepareExit();
498
499         return exit_status;
500 }
501
502
503 void LyX::prepareExit()
504 {
505         // Clear the clipboard and selection stack:
506         cap::clearCutStack();
507         cap::clearSelection();
508
509         // Set a flag that we do quitting from the program,
510         // so no refreshes are necessary.
511         quitting = true;
512
513         // close buffers first
514         pimpl_->buffer_list_.closeAll();
515
516         // do any other cleanup procedures now
517         if (package().temp_dir() != package().system_temp_dir()) {
518                 LYXERR(Debug::INFO) << "Deleting tmp dir "
519                                     << package().temp_dir().absFilename() << endl;
520
521                 if (!package().temp_dir().destroyDirectory()) {
522                         docstring const msg =
523                                 bformat(_("Unable to remove the temporary directory %1$s"),
524                                 from_utf8(package().temp_dir().absFilename()));
525                         Alert::warning(_("Unable to remove temporary directory"), msg);
526                 }
527         }
528
529         if (use_gui) {
530                 if (pimpl_->session_)
531                         pimpl_->session_->writeFile();
532                 pimpl_->session_.reset();
533                 pimpl_->lyx_server_.reset();
534                 pimpl_->lyx_socket_.reset();
535         }
536
537         // Kill the application object before exiting. This avoids crashes
538         // when exiting on Linux.
539         if (pimpl_->application_)
540                 pimpl_->application_.reset();
541 }
542
543
544 void LyX::earlyExit(int status)
545 {
546         BOOST_ASSERT(pimpl_->application_.get());
547         // LyX::pimpl_::application_ is not initialised at this
548         // point so it's safe to just exit after some cleanup.
549         prepareExit();
550         exit(status);
551 }
552
553
554 int LyX::init(int & argc, char * argv[])
555 {
556         // check for any spurious extra arguments
557         // other than documents
558         for (int argi = 1; argi < argc ; ++argi) {
559                 if (argv[argi][0] == '-') {
560                         lyxerr << to_utf8(
561                                 bformat(_("Wrong command line option `%1$s'. Exiting."),
562                                 from_utf8(argv[argi]))) << endl;
563                         return EXIT_FAILURE;
564                 }
565         }
566
567         // Initialization of LyX (reads lyxrc and more)
568         LYXERR(Debug::INIT) << "Initializing LyX::init..." << endl;
569         bool success = init();
570         LYXERR(Debug::INIT) << "Initializing LyX::init...done" << endl;
571         if (!success)
572                 return EXIT_FAILURE;
573
574         for (int argi = argc - 1; argi >= 1; --argi) {
575                 // get absolute path of file and add ".lyx" to
576                 // the filename if necessary
577                 pimpl_->files_to_load_.push_back(fileSearch(string(),
578                         os::internal_path(to_utf8(from_local8bit(argv[argi]))),
579                         "lyx", support::allow_unreadable));
580         }
581
582         if (first_start)
583                 pimpl_->files_to_load_.push_back(i18nLibFileSearch("examples", "splash.lyx"));
584
585         return EXIT_SUCCESS;
586 }
587
588
589 void LyX::addFileToLoad(FileName const & fname)
590 {
591         vector<FileName>::const_iterator cit = std::find(
592                 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
593                 fname);
594
595         if (cit == pimpl_->files_to_load_.end())
596                 pimpl_->files_to_load_.push_back(fname);
597 }
598
599
600 void LyX::loadFiles()
601 {
602         vector<FileName>::const_iterator it = pimpl_->files_to_load_.begin();
603         vector<FileName>::const_iterator end = pimpl_->files_to_load_.end();
604
605         for (; it != end; ++it) {
606                 if (it->empty())
607                         continue;
608
609                 Buffer * buf = pimpl_->buffer_list_.newBuffer(it->absFilename(), false);
610                 if (buf->loadLyXFile(*it)) {
611                         ErrorList const & el = buf->errorList("Parse");
612                         if (!el.empty())
613                                 for_each(el.begin(), el.end(),
614                                 boost::bind(&LyX::printError, this, _1));
615                 }
616                 else
617                         pimpl_->buffer_list_.release(buf);
618         }
619 }
620
621
622 void LyX::execBatchCommands()
623 {
624         // The advantage of doing this here is that the event loop
625         // is already started. So any need for interaction will be
626         // aknowledged.
627         restoreGuiSession();
628
629         // if reconfiguration is needed.
630         if (textclasslist.empty()) {
631             switch (Alert::prompt(
632                     _("No textclass is found"),
633                     _("LyX cannot continue because no textclass is found. "
634                       "You can either reconfigure normally, or reconfigure using "
635                       "default textclasses, or quit LyX."),
636                     0, 2,
637                     _("&Reconfigure"),
638                     _("&Use Default"),
639                     _("&Exit LyX")))
640                 {
641                 case 0:
642                         // regular reconfigure
643                         pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
644                         break;
645                 case 1:
646                         // reconfigure --without-latex-config
647                         pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
648                                 " --without-latex-config"));
649                         break;
650                 }
651                 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
652                 return;
653         }
654         
655         // Execute batch commands if available
656         if (pimpl_->batch_command.empty())
657                 return;
658
659         LYXERR(Debug::INIT) << "About to handle -x '"
660                 << pimpl_->batch_command << '\'' << endl;
661
662         pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
663 }
664
665
666 void LyX::restoreGuiSession()
667 {
668         LyXView * view = newLyXView();
669
670         // if there is no valid class list, do not load any file. 
671         if (textclasslist.empty())
672                 return;
673
674         // if some files were specified at command-line we assume that the
675         // user wants to edit *these* files and not to restore the session.
676         if (!pimpl_->files_to_load_.empty()) {
677                 for_each(pimpl_->files_to_load_.begin(),
678                         pimpl_->files_to_load_.end(),
679                         bind(&LyXView::loadLyXFile, view, _1, true));
680                 // clear this list to save a few bytes of RAM
681                 pimpl_->files_to_load_.clear();
682                 pimpl_->session_->lastOpened().clear();
683
684         } else if (lyxrc.load_session) {
685                 vector<FileName> const & lastopened = pimpl_->session_->lastOpened().getfiles();
686                 // do not add to the lastfile list since these files are restored from
687                 // last session, and should be already there (regular files), or should
688                 // not be added at all (help files).
689                 for_each(lastopened.begin(), lastopened.end(),
690                         bind(&LyXView::loadLyXFile, view, _1, false));
691
692                 // clear this list to save a few bytes of RAM
693                 pimpl_->session_->lastOpened().clear();
694         }
695
696         BufferList::iterator I = pimpl_->buffer_list_.begin();
697         BufferList::iterator end = pimpl_->buffer_list_.end();
698         for (; I != end; ++I) {
699                 Buffer * buf = *I;
700                 if (buf != buf->masterBuffer())
701                         continue;
702                 updateLabels(*buf);
703         }
704
705         // FIXME: Switch to the last loaded Buffer. This must not be the first one
706         // because the Buffer won't be connected in this case. The correct solution
707         // would be to avoid the manual connection of the current Buffer in LyXView.
708         if (!pimpl_->buffer_list_.empty())
709                 view->setBuffer(pimpl_->buffer_list_.last());
710 }
711
712
713 LyXView * LyX::newLyXView()
714 {
715         if (!lyx::use_gui)
716                 return 0;
717
718         // create the main window
719         LyXView * view = &pimpl_->application_->createView(geometryArg);
720
721         return view;
722 }
723
724 /*
725 Signals and Windows
726 ===================
727 The SIGHUP signal does not exist on Windows and does not need to be handled.
728
729 Windows handles SIGFPE and SIGSEGV signals as expected.
730
731 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
732 cause a new thread to be spawned. This may well result in unexpected
733 behaviour by the single-threaded LyX.
734
735 SIGTERM signals will come only from another process actually sending
736 that signal using 'raise' in Windows' POSIX compatability layer. It will
737 not come from the general "terminate process" methods that everyone
738 actually uses (and which can't be trapped). Killing an app 'politely' on
739 Windows involves first sending a WM_CLOSE message, something that is
740 caught already by the Qt frontend.
741
742 For more information see:
743
744 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
745 ...signals are mostly useless on Windows for a variety of reasons that are
746 Windows specific...
747
748 'UNIX Application Migration Guide, Chapter 9'
749 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
750
751 'How To Terminate an Application "Cleanly" in Win32'
752 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
753 */
754 extern "C" {
755
756 static void error_handler(int err_sig)
757 {
758         // Throw away any signals other than the first one received.
759         static sig_atomic_t handling_error = false;
760         if (handling_error)
761                 return;
762         handling_error = true;
763
764         // We have received a signal indicating a fatal error, so
765         // try and save the data ASAP.
766         LyX::cref().emergencyCleanup();
767
768         // These lyxerr calls may or may not work:
769
770         // Signals are asynchronous, so the main program may be in a very
771         // fragile state when a signal is processed and thus while a signal
772         // handler function executes.
773         // In general, therefore, we should avoid performing any
774         // I/O operations or calling most library and system functions from
775         // signal handlers.
776
777         // This shouldn't matter here, however, as we've already invoked
778         // emergencyCleanup.
779         switch (err_sig) {
780 #ifdef SIGHUP
781         case SIGHUP:
782                 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
783                 break;
784 #endif
785         case SIGFPE:
786                 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
787                 break;
788         case SIGSEGV:
789                 lyxerr << "\nlyx: SIGSEGV signal caught\n"
790                           "Sorry, you have found a bug in LyX. "
791                           "Please read the bug-reporting instructions "
792                           "in Help->Introduction and send us a bug report, "
793                           "if necessary. Thanks !\nBye." << endl;
794                 break;
795         case SIGINT:
796         case SIGTERM:
797                 // no comments
798                 break;
799         }
800
801         // Deinstall the signal handlers
802 #ifdef SIGHUP
803         signal(SIGHUP, SIG_DFL);
804 #endif
805         signal(SIGINT, SIG_DFL);
806         signal(SIGFPE, SIG_DFL);
807         signal(SIGSEGV, SIG_DFL);
808         signal(SIGTERM, SIG_DFL);
809
810 #ifdef SIGHUP
811         if (err_sig == SIGSEGV ||
812             (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
813 #else
814         if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
815 #endif
816                 support::abort();
817         exit(0);
818 }
819
820 }
821
822
823 void LyX::printError(ErrorItem const & ei)
824 {
825         docstring tmp = _("LyX: ") + ei.error + char_type(':')
826                 + ei.description;
827         std::cerr << to_utf8(tmp) << std::endl;
828 }
829
830
831 void LyX::initGuiFont()
832 {
833         if (lyxrc.roman_font_name.empty())
834                 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
835
836         if (lyxrc.sans_font_name.empty())
837                 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
838
839         if (lyxrc.typewriter_font_name.empty())
840                 lyxrc.typewriter_font_name
841                         = pimpl_->application_->typewriterFontName();
842 }
843
844
845 bool LyX::init()
846 {
847 #ifdef SIGHUP
848         signal(SIGHUP, error_handler);
849 #endif
850         signal(SIGFPE, error_handler);
851         signal(SIGSEGV, error_handler);
852         signal(SIGINT, error_handler);
853         signal(SIGTERM, error_handler);
854         // SIGPIPE can be safely ignored.
855
856         lyxrc.tempdir_path = package().temp_dir().absFilename();
857         lyxrc.document_path = package().document_dir().absFilename();
858
859         if (lyxrc.template_path.empty()) {
860                 lyxrc.template_path = addPath(package().system_support().absFilename(),
861                                               "templates");
862         }
863
864         //
865         // Read configuration files
866         //
867
868         // This one may have been distributed along with LyX.
869         if (!readRcFile("lyxrc.dist"))
870                 return false;
871
872         // Set the language defined by the distributor.
873         //setGuiLanguage(lyxrc.gui_language);
874
875         // Set the PATH correctly.
876 #if !defined (USE_POSIX_PACKAGING)
877         // Add the directory containing the LyX executable to the path
878         // so that LyX can find things like tex2lyx.
879         if (package().build_support().empty())
880                 prependEnvPath("PATH", package().binary_dir().absFilename());
881 #endif
882         if (!lyxrc.path_prefix.empty())
883                 prependEnvPath("PATH", lyxrc.path_prefix);
884
885         // Check that user LyX directory is ok.
886         if (queryUserLyXDir(package().explicit_user_support()))
887                 reconfigureUserLyXDir();
888
889         // no need for a splash when there is no GUI
890         if (!use_gui) {
891                 first_start = false;
892         }
893
894         // This one is generated in user_support directory by lib/configure.py.
895         if (!readRcFile("lyxrc.defaults"))
896                 return false;
897
898         // Query the OS to know what formats are viewed natively
899         formats.setAutoOpen();
900
901         // Read lyxrc.dist again to be able to override viewer auto-detection.
902         readRcFile("lyxrc.dist");
903
904         system_lyxrc = lyxrc;
905         system_formats = formats;
906         pimpl_->system_converters_ = pimpl_->converters_;
907         pimpl_->system_movers_ = pimpl_->movers_;
908         system_lcolor = lcolor;
909
910         // This one is edited through the preferences dialog.
911         if (!readRcFile("preferences"))
912                 return false;
913
914         if (!readEncodingsFile("encodings", "unicodesymbols"))
915                 return false;
916         if (!readLanguagesFile("languages"))
917                 return false;
918
919         // Load the layouts
920         LYXERR(Debug::INIT) << "Reading layouts..." << endl;
921         if (!LyXSetStyle())
922                 return false;
923         //...and the modules
924         moduleList.load();
925
926         // read keymap and ui files in batch mode as well
927         // because InsetInfo needs to know these to produce
928         // the correct output
929
930         // Set the language defined by the user.
931         //setGuiLanguage(lyxrc.gui_language);
932
933         // Set up command definitions
934         pimpl_->toplevel_cmddef_.reset(new CmdDef);
935         pimpl_->toplevel_cmddef_->read(lyxrc.def_file);
936
937         // Set up bindings
938         pimpl_->toplevel_keymap_.reset(new KeyMap);
939         pimpl_->toplevel_keymap_->read("site");
940         pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
941         // load user bind file user.bind
942         pimpl_->toplevel_keymap_->read("user");
943
944         pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
945
946         // Read menus
947         if (!readUIFile(lyxrc.ui_file))
948                 return false;
949
950         if (lyxerr.debugging(Debug::LYXRC))
951                 lyxrc.print();
952
953         os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
954         if (!lyxrc.path_prefix.empty())
955                 prependEnvPath("PATH", lyxrc.path_prefix);
956
957         FileName const document_path(lyxrc.document_path);
958         if (document_path.exists() && document_path.isDirectory())
959                 package().document_dir() = document_path;
960
961         package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
962         if (package().temp_dir().empty()) {
963                 Alert::error(_("Could not create temporary directory"),
964                              bformat(_("Could not create a temporary directory in\n"
965                                                     "%1$s. Make sure that this\n"
966                                                     "path exists and is writable and try again."),
967                                      from_utf8(lyxrc.tempdir_path)));
968                 // createLyXTmpDir() tries sufficiently hard to create a
969                 // usable temp dir, so the probability to come here is
970                 // close to zero. We therefore don't try to overcome this
971                 // problem with e.g. asking the user for a new path and
972                 // trying again but simply exit.
973                 return false;
974         }
975
976         LYXERR(Debug::INIT) << "LyX tmp dir: `"
977                             << package().temp_dir().absFilename()
978                             << '\'' << endl;
979
980         LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
981         pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
982
983         // This must happen after package initialization and after lyxrc is
984         // read, therefore it can't be done by a static object.
985         ConverterCache::init();
986
987         return true;
988 }
989
990
991 void LyX::emergencyCleanup() const
992 {
993         // what to do about tmpfiles is non-obvious. we would
994         // like to delete any we find, but our lyxdir might
995         // contain documents etc. which might be helpful on
996         // a crash
997
998         pimpl_->buffer_list_.emergencyWriteAll();
999         if (use_gui) {
1000                 if (pimpl_->lyx_server_)
1001                         pimpl_->lyx_server_->emergencyCleanup();
1002                 pimpl_->lyx_server_.reset();
1003                 pimpl_->lyx_socket_.reset();
1004         }
1005 }
1006
1007
1008 void LyX::deadKeyBindings(KeyMap * kbmap)
1009 {
1010         // bindKeyings for transparent handling of deadkeys
1011         // The keysyms are gotten from XFree86 X11R6
1012         kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1013         kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1014         kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1015         kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1016         kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1017         kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1018         kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1019         kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1020         kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1021         kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1022         // nothing with this name
1023         // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1024         kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1025         kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1026         // nothing with this name either...
1027         //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1028         kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1029         kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1030         kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1031 }
1032
1033
1034 // return true if file does not exist or is older than configure.py.
1035 static bool needsUpdate(string const & file)
1036 {
1037         // We cannot initialize configure_script directly because the package
1038         // is not initialized yet when  static objects are constructed.
1039         static FileName configure_script;
1040         static bool firstrun = true;
1041         if (firstrun) {
1042                 configure_script =
1043                         FileName(addName(package().system_support().absFilename(),
1044                                 "configure.py"));
1045                 firstrun = false;
1046         }
1047
1048         FileName absfile = 
1049                 FileName(addName(package().user_support().absFilename(), file));
1050         return !absfile.exists()
1051                 || configure_script.lastModified() > absfile.lastModified();
1052 }
1053
1054
1055 bool LyX::queryUserLyXDir(bool explicit_userdir)
1056 {
1057         // Does user directory exist?
1058         FileName const sup = package().user_support();
1059         if (sup.exists() && sup.isDirectory()) {
1060                 first_start = false;
1061
1062                 return needsUpdate("lyxrc.defaults")
1063                         || needsUpdate("lyxmodules.lst")
1064                         || needsUpdate("textclass.lst")
1065                         || needsUpdate("packages.lst");
1066         }
1067
1068         first_start = !explicit_userdir;
1069
1070         // If the user specified explicitly a directory, ask whether
1071         // to create it. If the user says "no", then exit.
1072         if (explicit_userdir &&
1073             Alert::prompt(
1074                     _("Missing user LyX directory"),
1075                     bformat(_("You have specified a non-existent user "
1076                                            "LyX directory, %1$s.\n"
1077                                            "It is needed to keep your own configuration."),
1078                             from_utf8(package().user_support().absFilename())),
1079                     1, 0,
1080                     _("&Create directory"),
1081                     _("&Exit LyX"))) {
1082                 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1083                 earlyExit(EXIT_FAILURE);
1084         }
1085
1086         lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1087                           from_utf8(sup.absFilename()))) << endl;
1088
1089         if (!sup.createDirectory(0755)) {
1090                 // Failed, so let's exit.
1091                 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1092                        << endl;
1093                 earlyExit(EXIT_FAILURE);
1094         }
1095
1096         return true;
1097 }
1098
1099
1100 bool LyX::readRcFile(string const & name)
1101 {
1102         LYXERR(Debug::INIT) << "About to read " << name << "... ";
1103
1104         FileName const lyxrc_path = libFileSearch(string(), name);
1105         if (!lyxrc_path.empty()) {
1106
1107                 LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
1108
1109                 if (lyxrc.read(lyxrc_path) < 0) {
1110                         showFileError(name);
1111                         return false;
1112                 }
1113         } else
1114                 LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
1115         return true;
1116
1117 }
1118
1119
1120 // Read the ui file `name'
1121 bool LyX::readUIFile(string const & name, bool include)
1122 {
1123         enum Uitags {
1124                 ui_menuset = 1,
1125                 ui_toolbars,
1126                 ui_toolbarset,
1127                 ui_include,
1128                 ui_last
1129         };
1130
1131         struct keyword_item uitags[ui_last - 1] = {
1132                 { "include", ui_include },
1133                 { "menuset", ui_menuset },
1134                 { "toolbars", ui_toolbars },
1135                 { "toolbarset", ui_toolbarset }
1136         };
1137
1138         // Ensure that a file is read only once (prevents include loops)
1139         static std::list<string> uifiles;
1140         std::list<string>::const_iterator it  = uifiles.begin();
1141         std::list<string>::const_iterator end = uifiles.end();
1142         it = std::find(it, end, name);
1143         if (it != end) {
1144                 LYXERR(Debug::INIT) << "UI file '" << name
1145                                     << "' has been read already. "
1146                                     << "Is this an include loop?"
1147                                     << endl;
1148                 return false;
1149         }
1150
1151         LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1152
1153
1154         FileName ui_path;
1155         if (include) {
1156                 ui_path = libFileSearch("ui", name, "inc");
1157                 if (ui_path.empty())
1158                         ui_path = libFileSearch("ui",
1159                                                 changeExtension(name, "inc"));
1160         }
1161         else
1162                 ui_path = libFileSearch("ui", name, "ui");
1163
1164         if (ui_path.empty()) {
1165                 LYXERR(Debug::INIT) << "Could not find " << name << endl;
1166                 showFileError(name);
1167                 return false;
1168         }
1169
1170         uifiles.push_back(name);
1171
1172         LYXERR(Debug::INIT) << "Found " << name
1173                             << " in " << ui_path << endl;
1174         Lexer lex(uitags, ui_last - 1);
1175         lex.setFile(ui_path);
1176         if (!lex.isOK()) {
1177                 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1178                        << endl;
1179         }
1180
1181         if (lyxerr.debugging(Debug::PARSER))
1182                 lex.printTable(lyxerr);
1183
1184         while (lex.isOK()) {
1185                 switch (lex.lex()) {
1186                 case ui_include: {
1187                         lex.next(true);
1188                         string const file = lex.getString();
1189                         if (!readUIFile(file, true))
1190                                 return false;
1191                         break;
1192                 }
1193                 case ui_menuset:
1194                         menubackend.read(lex);
1195                         break;
1196
1197                 case ui_toolbarset:
1198                         toolbarbackend.readToolbars(lex);
1199                         break;
1200
1201                 case ui_toolbars:
1202                         toolbarbackend.readToolbarSettings(lex);
1203                         break;
1204
1205                 default:
1206                         if (!rtrim(lex.getString()).empty())
1207                                 lex.printError("LyX::ReadUIFile: "
1208                                                "Unknown menu tag: `$$Token'");
1209                         break;
1210                 }
1211         }
1212         return true;
1213 }
1214
1215
1216 // Read the languages file `name'
1217 bool LyX::readLanguagesFile(string const & name)
1218 {
1219         LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1220
1221         FileName const lang_path = libFileSearch(string(), name);
1222         if (lang_path.empty()) {
1223                 showFileError(name);
1224                 return false;
1225         }
1226         languages.read(lang_path);
1227         return true;
1228 }
1229
1230
1231 // Read the encodings file `name'
1232 bool LyX::readEncodingsFile(string const & enc_name,
1233                             string const & symbols_name)
1234 {
1235         LYXERR(Debug::INIT) << "About to read " << enc_name << " and "
1236                             << symbols_name << "..." << endl;
1237
1238         FileName const symbols_path = libFileSearch(string(), symbols_name);
1239         if (symbols_path.empty()) {
1240                 showFileError(symbols_name);
1241                 return false;
1242         }
1243
1244         FileName const enc_path = libFileSearch(string(), enc_name);
1245         if (enc_path.empty()) {
1246                 showFileError(enc_name);
1247                 return false;
1248         }
1249         encodings.read(enc_path, symbols_path);
1250         return true;
1251 }
1252
1253
1254 namespace {
1255
1256 string batch;
1257
1258 /// return the the number of arguments consumed
1259 typedef boost::function<int(string const &, string const &)> cmd_helper;
1260
1261 int parse_dbg(string const & arg, string const &)
1262 {
1263         if (arg.empty()) {
1264                 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1265                 Debug::showTags(lyxerr);
1266                 exit(0);
1267         }
1268         lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1269
1270         lyxerr.level(Debug::value(arg));
1271         Debug::showLevel(lyxerr, lyxerr.level());
1272         return 1;
1273 }
1274
1275
1276 int parse_help(string const &, string const &)
1277 {
1278         lyxerr <<
1279                 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1280                   "Command line switches (case sensitive):\n"
1281                   "\t-help              summarize LyX usage\n"
1282                   "\t-userdir dir       set user directory to dir\n"
1283                   "\t-sysdir dir        set system directory to dir\n"
1284                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
1285                   "\t-dbg feature[,feature]...\n"
1286                   "                  select the features to debug.\n"
1287                   "                  Type `lyx -dbg' to see the list of features\n"
1288                   "\t-x [--execute] command\n"
1289                   "                  where command is a lyx command.\n"
1290                   "\t-e [--export] fmt\n"
1291                   "                  where fmt is the export format of choice.\n"
1292                   "                  Look on Tools->Preferences->File formats->Format\n"
1293                   "                  to get an idea which parameters should be passed.\n"
1294                   "\t-i [--import] fmt file.xxx\n"
1295                   "                  where fmt is the import format of choice\n"
1296                   "                  and file.xxx is the file to be imported.\n"
1297                   "\t-version        summarize version and build info\n"
1298                                "Check the LyX man page for more details.")) << endl;
1299         exit(0);
1300         return 0;
1301 }
1302
1303
1304 int parse_version(string const &, string const &)
1305 {
1306         lyxerr << "LyX " << lyx_version
1307                << " (" << lyx_release_date << ")" << endl;
1308         lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1309
1310         lyxerr << lyx_version_info << endl;
1311         exit(0);
1312         return 0;
1313 }
1314
1315
1316 int parse_sysdir(string const & arg, string const &)
1317 {
1318         if (arg.empty()) {
1319                 Alert::error(_("No system directory"),
1320                         _("Missing directory for -sysdir switch"));
1321                 exit(1);
1322         }
1323         cl_system_support = arg;
1324         return 1;
1325 }
1326
1327
1328 int parse_userdir(string const & arg, string const &)
1329 {
1330         if (arg.empty()) {
1331                 Alert::error(_("No user directory"),
1332                         _("Missing directory for -userdir switch"));
1333                 exit(1);
1334         }
1335         cl_user_support = arg;
1336         return 1;
1337 }
1338
1339
1340 int parse_execute(string const & arg, string const &)
1341 {
1342         if (arg.empty()) {
1343                 Alert::error(_("Incomplete command"),
1344                         _("Missing command string after --execute switch"));
1345                 exit(1);
1346         }
1347         batch = arg;
1348         return 1;
1349 }
1350
1351
1352 int parse_export(string const & type, string const &)
1353 {
1354         if (type.empty()) {
1355                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1356                                          "--export switch")) << endl;
1357                 exit(1);
1358         }
1359         batch = "buffer-export " + type;
1360         use_gui = false;
1361         return 1;
1362 }
1363
1364
1365 int parse_import(string const & type, string const & file)
1366 {
1367         if (type.empty()) {
1368                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1369                                          "--import switch")) << endl;
1370                 exit(1);
1371         }
1372         if (file.empty()) {
1373                 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1374                 exit(1);
1375         }
1376
1377         batch = "buffer-import " + type + ' ' + file;
1378         return 2;
1379 }
1380
1381
1382 int parse_geometry(string const & arg1, string const &)
1383 {
1384         geometryArg = arg1;
1385 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1386         // remove also the arg
1387         return 1;
1388 #else
1389         // don't remove "-geometry"
1390         return -1;
1391 #endif
1392 }
1393
1394
1395 } // namespace anon
1396
1397
1398 void LyX::easyParse(int & argc, char * argv[])
1399 {
1400         std::map<string, cmd_helper> cmdmap;
1401
1402         cmdmap["-dbg"] = parse_dbg;
1403         cmdmap["-help"] = parse_help;
1404         cmdmap["--help"] = parse_help;
1405         cmdmap["-version"] = parse_version;
1406         cmdmap["--version"] = parse_version;
1407         cmdmap["-sysdir"] = parse_sysdir;
1408         cmdmap["-userdir"] = parse_userdir;
1409         cmdmap["-x"] = parse_execute;
1410         cmdmap["--execute"] = parse_execute;
1411         cmdmap["-e"] = parse_export;
1412         cmdmap["--export"] = parse_export;
1413         cmdmap["-i"] = parse_import;
1414         cmdmap["--import"] = parse_import;
1415         cmdmap["-geometry"] = parse_geometry;
1416
1417         for (int i = 1; i < argc; ++i) {
1418                 std::map<string, cmd_helper>::const_iterator it
1419                         = cmdmap.find(argv[i]);
1420
1421                 // don't complain if not found - may be parsed later
1422                 if (it == cmdmap.end())
1423                         continue;
1424
1425                 string const arg =
1426                         (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1427                 string const arg2 =
1428                         (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1429
1430                 int const remove = 1 + it->second(arg, arg2);
1431
1432                 // Now, remove used arguments by shifting
1433                 // the following ones remove places down.
1434                 if (remove > 0) {
1435                         argc -= remove;
1436                         for (int j = i; j < argc; ++j)
1437                                 argv[j] = argv[j + remove];
1438                         --i;
1439                 }
1440         }
1441
1442         pimpl_->batch_command = batch;
1443 }
1444
1445
1446 FuncStatus getStatus(FuncRequest const & action)
1447 {
1448         return LyX::ref().lyxFunc().getStatus(action);
1449 }
1450
1451
1452 void dispatch(FuncRequest const & action)
1453 {
1454         LyX::ref().lyxFunc().dispatch(action);
1455 }
1456
1457
1458 BufferList & theBufferList()
1459 {
1460         return LyX::ref().bufferList();
1461 }
1462
1463
1464 LyXFunc & theLyXFunc()
1465 {
1466         return LyX::ref().lyxFunc();
1467 }
1468
1469
1470 Server & theServer()
1471 {
1472         // FIXME: this should not be use_gui dependent
1473         BOOST_ASSERT(use_gui);
1474         return LyX::ref().server();
1475 }
1476
1477
1478 ServerSocket & theServerSocket()
1479 {
1480         // FIXME: this should not be use_gui dependent
1481         BOOST_ASSERT(use_gui);
1482         return LyX::ref().socket();
1483 }
1484
1485
1486 KeyMap & theTopLevelKeymap()
1487 {
1488         return LyX::ref().topLevelKeymap();
1489 }
1490
1491
1492 Converters & theConverters()
1493 {
1494         return  LyX::ref().converters();
1495 }
1496
1497
1498 Converters & theSystemConverters()
1499 {
1500         return  LyX::ref().systemConverters();
1501 }
1502
1503
1504 Movers & theMovers()
1505 {
1506         return  LyX::ref().pimpl_->movers_;
1507 }
1508
1509
1510 Mover const & getMover(std::string  const & fmt)
1511 {
1512         return  LyX::ref().pimpl_->movers_(fmt);
1513 }
1514
1515
1516 void setMover(std::string const & fmt, std::string const & command)
1517 {
1518         LyX::ref().pimpl_->movers_.set(fmt, command);
1519 }
1520
1521
1522 Movers & theSystemMovers()
1523 {
1524         return  LyX::ref().pimpl_->system_movers_;
1525 }
1526
1527
1528 Messages & getMessages(std::string const & language)
1529 {
1530         return LyX::ref().getMessages(language);
1531 }
1532
1533
1534 Messages & getGuiMessages()
1535 {
1536         return LyX::ref().getGuiMessages();
1537 }
1538
1539 } // namespace lyx