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