]> git.lyx.org Git - lyx.git/blob - src/LyX.cpp
prepare Qt 5.6 builds
[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 "AppleSpellChecker.h"
21 #include "AspellChecker.h"
22 #include "Buffer.h"
23 #include "BufferList.h"
24 #include "CmdDef.h"
25 #include "ColorSet.h"
26 #include "ConverterCache.h"
27 #include "Converter.h"
28 #include "CutAndPaste.h"
29 #include "EnchantChecker.h"
30 #include "Encoding.h"
31 #include "ErrorList.h"
32 #include "Format.h"
33 #include "FuncStatus.h"
34 #include "HunspellChecker.h"
35 #include "KeyMap.h"
36 #include "Language.h"
37 #include "LaTeXFonts.h"
38 #include "LayoutFile.h"
39 #include "Lexer.h"
40 #include "LyX.h"
41 #include "LyXAction.h"
42 #include "LyXRC.h"
43 #include "ModuleList.h"
44 #include "Mover.h"
45 #include "Server.h"
46 #include "ServerSocket.h"
47 #include "Session.h"
48 #include "WordList.h"
49
50 #include "frontends/alert.h"
51 #include "frontends/Application.h"
52
53 #include "support/ConsoleApplication.h"
54 #include "support/lassert.h"
55 #include "support/debug.h"
56 #include "support/environment.h"
57 #include "support/ExceptionMessage.h"
58 #include "support/filetools.h"
59 #include "support/gettext.h"
60 #include "support/lstrings.h"
61 #include "support/Messages.h"
62 #include "support/os.h"
63 #include "support/Package.h"
64
65 #include "support/bind.h"
66 #include <boost/scoped_ptr.hpp>
67
68 #include <algorithm>
69 #include <iostream>
70 #include <csignal>
71 #include <map>
72 #include <stdlib.h>
73 #include <string>
74 #include <vector>
75
76 using namespace std;
77 using namespace lyx::support;
78
79 #if defined (USE_MACOSX_PACKAGING)
80 #include <crt_externs.h>
81 #endif
82
83 namespace lyx {
84
85 namespace Alert = frontend::Alert;
86 namespace os = support::os;
87
88
89
90 // Are we using the GUI at all?  We default to true and this is changed
91 // to false when the export feature is used.
92
93 bool use_gui = true;
94
95
96 // We default to open documents in an already running instance, provided that
97 // the lyxpipe has been setup. This can be overridden either on the command
98 // line or through preference settings.
99
100 RunMode run_mode = PREFERRED;
101
102
103 // Tell what files can be silently overwritten during batch export.
104 // Possible values are: NO_FILES, MAIN_FILE, ALL_FILES, UNSPECIFIED.
105 // Unless specified on command line (through the -f switch) or through the
106 // environment variable LYX_FORCE_OVERWRITE, the default will be MAIN_FILE.
107
108 OverwriteFiles force_overwrite = UNSPECIFIED;
109
110
111 namespace {
112
113 // Filled with the command line arguments "foo" of "-sysdir foo" or
114 // "-userdir foo".
115 string cl_system_support;
116 string cl_user_support;
117
118 string geometryArg;
119
120 LyX * singleton_ = 0;
121
122 void showFileError(string const & error)
123 {
124         Alert::warning(_("Could not read configuration file"),
125                        bformat(_("Error while reading the configuration file\n%1$s.\n"
126                            "Please check your installation."), from_utf8(error)));
127 }
128
129 } // namespace anon
130
131 /// The main application class private implementation.
132 struct LyX::Impl {
133         Impl()
134                 : latexfonts_(0), spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0)
135         {}
136
137         ~Impl()
138         {
139                 delete latexfonts_;
140                 delete apple_spell_checker_;
141                 delete aspell_checker_;
142                 delete enchant_checker_;
143                 delete hunspell_checker_;
144         }
145
146         ///
147         BufferList buffer_list_;
148         ///
149         KeyMap toplevel_keymap_;
150         ///
151         CmdDef toplevel_cmddef_;
152         ///
153         boost::scoped_ptr<Server> lyx_server_;
154         ///
155         boost::scoped_ptr<ServerSocket> lyx_socket_;
156         ///
157         boost::scoped_ptr<frontend::Application> application_;
158         /// lyx session, containing lastfiles, lastfilepos, and lastopened
159         boost::scoped_ptr<Session> session_;
160
161         /// Files to load at start.
162         vector<string> files_to_load_;
163
164         /// The messages translators.
165         map<string, Messages> messages_;
166
167         /// The file converters.
168         Converters converters_;
169
170         // The system converters copy after reading lyxrc.defaults.
171         Converters system_converters_;
172
173         ///
174         Movers movers_;
175         ///
176         Movers system_movers_;
177
178         /// the parsed command line batch command if any
179         vector<string> batch_commands;
180
181         ///
182         LaTeXFonts * latexfonts_;
183
184         ///
185         SpellChecker * spell_checker_;
186         ///
187         SpellChecker * apple_spell_checker_;
188         ///
189         SpellChecker * aspell_checker_;
190         ///
191         SpellChecker * enchant_checker_;
192         ///
193         SpellChecker * hunspell_checker_;
194 };
195
196
197 /// The main application class for console mode
198 class LyXConsoleApp : public ConsoleApplication
199 {
200 public:
201         LyXConsoleApp(LyX * lyx, int & argc, char * argv[])
202                 : ConsoleApplication(lyx_package, argc, argv), lyx_(lyx),
203                   argc_(argc), argv_(argv)
204         {
205         }
206         void doExec()
207         {
208                 int const exit_status = lyx_->execWithoutGui(argc_, argv_);
209                 exit(exit_status);
210         }
211 private:
212         LyX * lyx_;
213         int & argc_;
214         char ** argv_;
215 };
216
217
218 ///
219 frontend::Application * theApp()
220 {
221         if (singleton_)
222                 return singleton_->pimpl_->application_.get();
223         else
224                 return 0;
225 }
226
227
228 LyX::~LyX()
229 {
230         delete pimpl_;
231         singleton_ = 0;
232         WordList::cleanupWordLists();
233 }
234
235
236 void lyx_exit(int exit_code)
237 {
238         if (exit_code)
239                 // Something wrong happened so better save everything, just in
240                 // case.
241                 emergencyCleanup();
242
243 #ifndef NDEBUG
244         // Properly crash in debug mode in order to get a useful backtrace.
245         abort();
246 #endif
247
248         // In release mode, try to exit gracefully.
249         if (theApp())
250                 theApp()->exit(exit_code);
251         else
252                 exit(exit_code);
253 }
254
255
256 LyX::LyX()
257         : first_start(false)
258 {
259         singleton_ = this;
260         pimpl_ = new Impl;
261 }
262
263
264 Messages & LyX::messages(string const & language)
265 {
266         map<string, Messages>::iterator it = pimpl_->messages_.find(language);
267
268         if (it != pimpl_->messages_.end())
269                 return it->second;
270
271         pair<map<string, Messages>::iterator, bool> result =
272                         pimpl_->messages_.insert(make_pair(language, Messages(language)));
273
274         LATTEST(result.second);
275         return result.first->second;
276 }
277
278
279 int LyX::exec(int & argc, char * argv[])
280 {
281         // Minimal setting of locale before parsing command line
282         try {
283                 init_package(os::utf8_argv(0), string(), string());
284                 // we do not get to this point when init_package throws an exception
285                 setLocale();
286         } catch (ExceptionMessage const & message) {
287                 LYXERR(Debug::LOCALE, message.title_ + ", " + message.details_);
288         }
289
290         // Here we need to parse the command line. At least
291         // we need to parse for "-dbg" and "-help"
292         easyParse(argc, argv);
293
294         try {
295                 init_package(os::utf8_argv(0), cl_system_support, cl_user_support);
296         } catch (ExceptionMessage const & message) {
297                 if (message.type_ == ErrorException) {
298                         Alert::error(message.title_, message.details_);
299                         lyx_exit(1);
300                 } else if (message.type_ == WarningException) {
301                         Alert::warning(message.title_, message.details_);
302                 }
303         }
304
305         // Reinit the messages machinery in case package() knows
306         // something interesting about the locale directory.
307         setLocale();
308
309         if (!use_gui) {
310                 LyXConsoleApp app(this, argc, argv);
311
312                 // Reestablish our defaults, as Qt overwrites them
313                 // after creating app
314                 setLocale();//???
315
316                 return app.exec();
317         }
318
319         // Let the frontend parse and remove all arguments that it knows
320         pimpl_->application_.reset(createApplication(argc, argv));
321
322         // Reestablish our defaults, as Qt overwrites them
323         // after createApplication()
324         setLocale();//???
325
326         // Parse and remove all known arguments in the LyX singleton
327         // Give an error for all remaining ones.
328         int exit_status = init(argc, argv);
329         if (exit_status) {
330                 // Kill the application object before exiting.
331                 pimpl_->application_.reset();
332                 use_gui = false;
333                 prepareExit();
334                 return exit_status;
335         }
336
337         // If not otherwise specified by a command line option or
338         // by preferences, we default to reuse a running instance.
339         if (run_mode == PREFERRED)
340                 run_mode = USE_REMOTE;
341
342         // FIXME
343         /* Create a CoreApplication class that will provide the main event loop
344         * and the socket callback registering. With Qt, only QtCore
345         * library would be needed.
346         * When this is done, a server_mode could be created and the following two
347         * line would be moved out from here.
348         * However, note that the first of the two lines below triggers the
349         * "single instance" behavior, which should occur right at this point.
350         */
351         // Note: socket callback must be registered after init(argc, argv)
352         // such that package().temp_dir() is properly initialized.
353         pimpl_->lyx_server_.reset(new Server(lyxrc.lyxpipes));
354         pimpl_->lyx_socket_.reset(new ServerSocket(
355                         FileName(package().temp_dir().absFileName() + "/lyxsocket")));
356
357         // Start the real execution loop.
358         if (!theServer().deferredLoadingToOtherInstance())
359                 exit_status = pimpl_->application_->exec();
360         else if (!pimpl_->files_to_load_.empty()) {
361                 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
362                 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
363                 lyxerr << _("The following files could not be loaded:") << endl;
364                 for (; it != end; ++it)
365                         lyxerr << *it << endl;
366         }
367
368         prepareExit();
369
370         return exit_status;
371 }
372
373
374 void LyX::prepareExit()
375 {
376         // Clear the clipboard and selection stack:
377         cap::clearCutStack();
378         cap::clearSelection();
379
380         // Write the index file of the converter cache
381         ConverterCache::get().writeIndex();
382
383         // close buffers first
384         pimpl_->buffer_list_.closeAll();
385
386         // register session changes and shutdown server and socket
387         if (use_gui) {
388                 if (pimpl_->session_)
389                         pimpl_->session_->writeFile();
390                 pimpl_->session_.reset();
391                 pimpl_->lyx_server_.reset();
392                 pimpl_->lyx_socket_.reset();
393         }
394
395         // do any other cleanup procedures now
396         if (package().temp_dir() != package().system_temp_dir()) {
397                 string const abs_tmpdir = package().temp_dir().absFileName();
398                 if (!contains(package().temp_dir().absFileName(), "lyx_tmpdir")) {
399                         docstring const msg =
400                                 bformat(_("%1$s does not appear like a LyX created temporary directory."),
401                                 from_utf8(abs_tmpdir));
402                         Alert::warning(_("Cannot remove temporary directory"), msg);
403                 } else {
404                         LYXERR(Debug::INFO, "Deleting tmp dir "
405                                 << package().temp_dir().absFileName());
406                         if (!package().temp_dir().destroyDirectory()) {
407                                 LYXERR0(bformat(_("Unable to remove the temporary directory %1$s"),
408                                         from_utf8(package().temp_dir().absFileName())));
409                         }
410                 }
411         }
412
413         // Kill the application object before exiting. This avoids crashes
414         // when exiting on Linux.
415         pimpl_->application_.reset();
416 }
417
418
419 void LyX::earlyExit(int status)
420 {
421         LATTEST(pimpl_->application_.get());
422         // LyX::pimpl_::application_ is not initialised at this
423         // point so it's safe to just exit after some cleanup.
424         prepareExit();
425         exit(status);
426 }
427
428
429 int LyX::init(int & argc, char * argv[])
430 {
431         // check for any spurious extra arguments
432         // other than documents
433         for (int argi = 1; argi < argc ; ++argi) {
434                 if (argv[argi][0] == '-') {
435                         lyxerr << to_utf8(
436                                 bformat(_("Wrong command line option `%1$s'. Exiting."),
437                                 from_utf8(os::utf8_argv(argi)))) << endl;
438                         return EXIT_FAILURE;
439                 }
440         }
441
442         // Initialization of LyX (reads lyxrc and more)
443         LYXERR(Debug::INIT, "Initializing LyX::init...");
444         bool success = init();
445         LYXERR(Debug::INIT, "Initializing LyX::init...done");
446         if (!success)
447                 return EXIT_FAILURE;
448
449         // Remaining arguments are assumed to be files to load.
450         for (int argi = 1; argi < argc; ++argi)
451                 pimpl_->files_to_load_.push_back(os::utf8_argv(argi));
452
453         if (!use_gui && pimpl_->files_to_load_.empty()) {
454                 lyxerr << to_utf8(_("Missing filename for this operation.")) << endl;
455                 return EXIT_FAILURE;
456         }
457
458         if (first_start) {
459                 pimpl_->files_to_load_.push_back(
460                         i18nLibFileSearch("examples", "splash.lyx").absFileName());
461         }
462
463         return EXIT_SUCCESS;
464 }
465
466
467 int LyX::execWithoutGui(int & argc, char * argv[])
468 {
469         int exit_status = init(argc, argv);
470         if (exit_status) {
471                 prepareExit();
472                 return exit_status;
473         }
474
475         // Used to keep track of which buffers were explicitly loaded by user request.
476         // This is necessary because master and child document buffers are loaded, even 
477         // if they were not named on the command line. We do not want to dispatch to
478         // those.
479         vector<Buffer *> command_line_buffers;
480
481         // Load the files specified on the command line
482         vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
483         vector<string>::const_iterator end = pimpl_->files_to_load_.end();
484         for (; it != end; ++it) {
485                 // get absolute path of file and add ".lyx" to the filename if necessary
486                 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
487                                                                                                                                 may_not_exist);
488
489                 if (fname.empty())
490                         continue;
491
492                 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFileName());
493                 LYXERR(Debug::FILES, "Loading " << fname);
494                 if (buf->loadLyXFile() == Buffer::ReadSuccess) {
495                         ErrorList const & el = buf->errorList("Parse");
496                         if (!el.empty())
497                                         for_each(el.begin(), el.end(),
498                                                                          bind(&LyX::printError, this, _1));
499                         command_line_buffers.push_back(buf);
500                 } else {
501                         pimpl_->buffer_list_.release(buf);
502                         docstring const error_message =
503                                         bformat(_("LyX failed to load the following file: %1$s"),
504                                                                         from_utf8(fname.absFileName()));
505                         lyxerr << to_utf8(error_message) << endl;
506                         exit_status = 1; // failed
507                 }
508         }
509
510         if (exit_status || pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
511                 prepareExit();
512                 return exit_status;
513         }
514
515         // Iterate through the buffers that were specified on the command line
516         bool final_success = false;
517         vector<Buffer *>::iterator buf_it = command_line_buffers.begin();
518         for (; buf_it != command_line_buffers.end(); ++buf_it) {
519                 Buffer * buf = *buf_it;
520                 vector<string>::const_iterator bcit  = pimpl_->batch_commands.begin();
521                 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
522                 DispatchResult dr;
523                 for (; bcit != bcend; ++bcit) {
524                         LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit);
525                         buf->dispatch(*bcit, dr);
526                         final_success |= !dr.error();
527                 }
528         }
529         prepareExit();
530         return !final_success;
531 }
532
533
534 void execBatchCommands()
535 {
536         LAPPERR(singleton_);
537         singleton_->execCommands();
538 }
539
540
541 void LyX::execCommands()
542 {
543         // The advantage of doing this here is that the event loop
544         // is already started. So any need for interaction will be
545         // aknowledged.
546
547         // if reconfiguration is needed.
548         if (LayoutFileList::get().empty()) {
549                 switch (Alert::prompt(
550                         _("No textclass is found"),
551                         _("LyX will only have minimal functionality because no textclasses "
552                                 "have been found. You can either try to reconfigure LyX normally, "
553                                 "try to reconfigure without checking your LaTeX installation, or continue."),
554                         0, 2,
555                         _("&Reconfigure"),
556                         _("&Without LaTeX"),
557                         _("&Continue")))
558                 {
559                 case 0:
560                         // regular reconfigure
561                         lyx::dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
562                         break;
563                 case 1:
564                         // reconfigure --without-latex-config
565                         lyx::dispatch(FuncRequest(LFUN_RECONFIGURE,
566                                 " --without-latex-config"));
567                         break;
568                 default:
569                         break;
570                 }
571         }
572
573         // create the first main window
574         lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
575
576         if (!pimpl_->files_to_load_.empty()) {
577                 // if some files were specified at command-line we assume that the
578                 // user wants to edit *these* files and not to restore the session.
579                 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
580                         lyx::dispatch(
581                                 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
582                 }
583                 // clear this list to save a few bytes of RAM
584                 pimpl_->files_to_load_.clear();
585         } else
586                 pimpl_->application_->restoreGuiSession();
587
588         // Execute batch commands if available
589         if (pimpl_->batch_commands.empty())
590                 return;
591
592         vector<string>::const_iterator bcit  = pimpl_->batch_commands.begin();
593         vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
594         for (; bcit != bcend; ++bcit) {
595                 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
596                 lyx::dispatch(lyxaction.lookupFunc(*bcit));
597         }
598 }
599
600
601 /*
602 Signals and Windows
603 ===================
604 The SIGHUP signal does not exist on Windows and does not need to be handled.
605
606 Windows handles SIGFPE and SIGSEGV signals as expected.
607
608 Ctrl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
609 cause a new thread to be spawned. This may well result in unexpected
610 behaviour by the single-threaded LyX.
611
612 SIGTERM signals will come only from another process actually sending
613 that signal using 'raise' in Windows' POSIX compatability layer. It will
614 not come from the general "terminate process" methods that everyone
615 actually uses (and which can't be trapped). Killing an app 'politely' on
616 Windows involves first sending a WM_CLOSE message, something that is
617 caught already by the Qt frontend.
618
619 For more information see:
620
621 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
622 ...signals are mostly useless on Windows for a variety of reasons that are
623 Windows specific...
624
625 'UNIX Application Migration Guide, Chapter 9'
626 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
627
628 'How To Terminate an Application "Cleanly" in Win32'
629 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
630 */
631 extern "C" {
632
633 static void error_handler(int err_sig)
634 {
635         // Throw away any signals other than the first one received.
636         static sig_atomic_t handling_error = false;
637         if (handling_error)
638                 return;
639         handling_error = true;
640
641         // We have received a signal indicating a fatal error, so
642         // try and save the data ASAP.
643         emergencyCleanup();
644
645         // These lyxerr calls may or may not work:
646
647         // Signals are asynchronous, so the main program may be in a very
648         // fragile state when a signal is processed and thus while a signal
649         // handler function executes.
650         // In general, therefore, we should avoid performing any
651         // I/O operations or calling most library and system functions from
652         // signal handlers.
653
654         // This shouldn't matter here, however, as we've already invoked
655         // emergencyCleanup.
656         docstring msg;
657         switch (err_sig) {
658 #ifdef SIGHUP
659         case SIGHUP:
660                 msg = _("SIGHUP signal caught!\nBye.");
661                 break;
662 #endif
663         case SIGFPE:
664                 msg = _("SIGFPE signal caught!\nBye.");
665                 break;
666         case SIGSEGV:
667                 msg = _("SIGSEGV signal caught!\n"
668                           "Sorry, you have found a bug in LyX, "
669                           "hope you have not lost any data.\n"
670                           "Please read the bug-reporting instructions "
671                           "in 'Help->Introduction' and send us a bug report, "
672                           "if necessary. Thanks!\nBye.");
673                 break;
674         case SIGINT:
675         case SIGTERM:
676                 // no comments
677                 break;
678         }
679
680         if (!msg.empty()) {
681                 lyxerr << "\nlyx: " << msg << endl;
682                 // try to make a GUI message
683                 Alert::error(_("LyX crashed!"), msg, true);
684         }
685
686         // Deinstall the signal handlers
687 #ifdef SIGHUP
688         signal(SIGHUP, SIG_DFL);
689 #endif
690         signal(SIGINT, SIG_DFL);
691         signal(SIGFPE, SIG_DFL);
692         signal(SIGSEGV, SIG_DFL);
693         signal(SIGTERM, SIG_DFL);
694
695 #ifdef SIGHUP
696         if (err_sig == SIGSEGV ||
697                 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty())) {
698 #else
699         if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty()) {
700 #endif
701 #ifdef _MSC_VER
702                 // with abort() it crashes again.
703                 exit(err_sig);
704 #else
705                 abort();
706 #endif
707         }
708
709         exit(0);
710 }
711
712 }
713
714
715 void LyX::printError(ErrorItem const & ei)
716 {
717         docstring tmp = _("LyX: ") + ei.error + char_type(':')
718                 + ei.description;
719         cerr << to_utf8(tmp) << endl;
720 }
721
722 #if defined (USE_MACOSX_PACKAGING)
723 namespace {
724         // Unexposed--extract an environment variable name from its NAME=VALUE
725         // representation
726         std::string varname(const char* line)
727         {
728                 size_t nameLen = strcspn(line, "=");
729                 if (nameLen == strlen(line)) {
730                         return std::string();
731                 } else {
732                         return std::string(line, nameLen);
733                 }
734         }
735 }
736
737 void cleanDuplicateEnvVars()
738 {
739         std::set<std::string> seen;
740         std::set<std::string> dupes;
741
742         // Create a list of the environment variables that appear more than once
743         for (char **read = *_NSGetEnviron(); *read; read++) {
744                 std::string name = varname(*read);
745                 if (name.size() == 0) {
746                         continue;
747                 }
748                 if (seen.find(name) != seen.end()) {
749                         dupes.insert(name);
750                 } else {
751                         seen.insert(name);
752                 }
753         }
754
755         // Loop over the list of duplicated variables
756         std::set<std::string>::iterator dupe = dupes.begin();
757         std::set<std::string>::iterator const dend = dupes.end();
758         for (; dupe != dend; ++dupe) {
759                 const char *name = (*dupe).c_str();
760                 char *val = getenv(name);
761                 if (val != NULL) {
762                         LYXERR(Debug::INIT, "Duplicate environment variable: " << name);
763                         // unsetenv removes *all* instances of the variable from the environment
764                         unsetenv(name);
765
766                         // replace with the value from getenv (in practice appears to be the
767                         // first value in the list)
768                         setenv(name, val, 0);
769                 }
770         }
771 }
772 #endif
773
774
775 static void initTemplatePath()
776 {
777         FileName const package_template_path =
778                 FileName(addName(package().system_support().absFileName(), "templates"));
779
780         if (lyxrc.template_path.empty()) {
781                 lyxrc.template_path = package_template_path.absFileName();
782         }
783 #if defined (USE_MACOSX_PACKAGING)
784         FileName const user_template_path =
785                 FileName(addName(package().user_support().absFileName(), "templates"));
786
787         if (package_template_path != FileName(lyxrc.template_path) &&
788                 user_template_path != FileName(lyxrc.template_path))
789         {
790                 return;
791         }
792         FileName const user_template_link =
793                 FileName(addName(user_template_path.absFileName(),"SystemTemplates"));
794         if (user_template_link.isSymLink() && !equivalent(user_template_link, package_template_path)) {
795                 user_template_link.removeFile();
796         }
797         if (!user_template_link.exists()) {
798                 if (!package_template_path.link(user_template_link)) {
799                         FileName const user_support = package().user_support();
800                         if (user_support.exists() && user_support.isDirectory()) {
801                                 LYXERR(Debug::INIT, "Cannot create symlink " + user_template_link.absFileName());
802                                 lyxrc.template_path = package_template_path.absFileName();
803                         }
804                         return;
805                 }
806                 LYXERR(Debug::INIT, "Symlink \"" << user_template_link.absFileName() << "\" created.");
807         }
808         lyxrc.template_path = user_template_path.absFileName();
809 #endif
810 }
811
812
813 bool LyX::init()
814 {
815 #ifdef SIGHUP
816         signal(SIGHUP, error_handler);
817 #endif
818         signal(SIGFPE, error_handler);
819         signal(SIGSEGV, error_handler);
820         signal(SIGINT, error_handler);
821         signal(SIGTERM, error_handler);
822         // SIGPIPE can be safely ignored.
823
824 #if defined (USE_MACOSX_PACKAGING)
825         cleanDuplicateEnvVars();
826 #endif
827
828         lyxrc.tempdir_path = package().temp_dir().absFileName();
829         lyxrc.document_path = package().document_dir().absFileName();
830
831         if (lyxrc.example_path.empty()) {
832                 lyxrc.example_path = addPath(package().system_support().absFileName(),
833                                               "examples");
834         }
835         initTemplatePath();
836
837         // init LyXDir environment variable
838         string const lyx_dir = package().lyx_dir().absFileName();
839         LYXERR(Debug::INIT, "Setting LyXDir... to \"" << lyx_dir << "\"");
840         if (!setEnv("LyXDir", lyx_dir))
841                 LYXERR(Debug::INIT, "\t... failed!");
842
843         if (package().explicit_user_support() && getEnv(LYX_USERDIR_VER).empty()) {
844                 // -userdir was given on the command line.
845                 // Make it available to child processes, otherwise tex2lyx
846                 // would not find all layout files, and other converters might
847                 // use it as well.
848                 string const user_dir = package().user_support().absFileName();
849                 LYXERR(Debug::INIT, "Setting " LYX_USERDIR_VER "... to \""
850                                     << user_dir << '"');
851                 if (!setEnv(LYX_USERDIR_VER, user_dir))
852                         LYXERR(Debug::INIT, "\t... failed!");
853         }
854
855         //
856         // Read configuration files
857         //
858
859         // This one may have been distributed along with LyX.
860         if (!readRcFile("lyxrc.dist"))
861                 return false;
862
863         // Set the PATH correctly.
864 #if !defined (USE_POSIX_PACKAGING) && !defined (USE_HAIKU_PACKAGING)
865         // Add the directory containing the LyX executable to the path
866         // so that LyX can find things like tex2lyx.
867         if (package().build_support().empty())
868                 prependEnvPath("PATH", package().binary_dir().absFileName());
869 #endif
870         if (!lyxrc.path_prefix.empty())
871                 prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix));
872
873         // Check that user LyX directory is ok.
874         {
875                 string const lock_file = package().getConfigureLockName();
876                 int fd = fileLock(lock_file.c_str());
877
878                 if (queryUserLyXDir(package().explicit_user_support())) {
879                         package().reconfigureUserLyXDir("");
880                         // Now the user directory is present on first start.
881                         initTemplatePath();
882                 }
883                 fileUnlock(fd, lock_file.c_str());
884         }
885
886         if (!use_gui) {
887                 // No need for a splash when there is no GUI
888                 first_start = false;
889                 // Default is to overwrite the main file during export, unless
890                 // the -f switch was specified or LYX_FORCE_OVERWRITE was set
891                 if (force_overwrite == UNSPECIFIED) {
892                         string const what = getEnv("LYX_FORCE_OVERWRITE");
893                         if (what == "all")
894                                 force_overwrite = ALL_FILES;
895                         else if (what == "none")
896                                 force_overwrite = NO_FILES;
897                         else
898                                 force_overwrite = MAIN_FILE;
899                 }
900         }
901
902         // This one is generated in user_support directory by lib/configure.py.
903         if (!readRcFile("lyxrc.defaults"))
904                 return false;
905
906         // Query the OS to know what formats are viewed natively
907         formats.setAutoOpen();
908
909         // Read lyxrc.dist again to be able to override viewer auto-detection.
910         readRcFile("lyxrc.dist");
911
912         system_lyxrc = lyxrc;
913         system_formats = formats;
914         pimpl_->system_converters_ = pimpl_->converters_;
915         pimpl_->system_movers_ = pimpl_->movers_;
916         system_lcolor = lcolor;
917
918         // This one is edited through the preferences dialog.
919         if (!readRcFile("preferences", true))
920                 return false;
921
922         // The language may have been set to someting useful through prefs
923         setLocale();
924
925         if (!readEncodingsFile("encodings", "unicodesymbols"))
926                 return false;
927         if (!readLanguagesFile("languages"))
928                 return false;
929
930         LYXERR(Debug::INIT, "Reading layouts...");
931         // Load the layouts
932         LayoutFileList::get().read();
933         //...and the modules
934         theModuleList.read();
935
936         // read keymap and ui files in batch mode as well
937         // because InsetInfo needs to know these to produce
938         // the correct output
939
940         // Set up command definitions
941         pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
942
943         // FIXME
944         // Set up bindings
945         pimpl_->toplevel_keymap_.read("site");
946         pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
947         // load user bind file user.bind
948         pimpl_->toplevel_keymap_.read("user", 0, KeyMap::MissingOK);
949
950         if (lyxerr.debugging(Debug::LYXRC))
951                 lyxrc.print();
952
953         os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
954         // Prepend path prefix a second time to take the user preferences into a account
955         if (!lyxrc.path_prefix.empty())
956                 prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix));
957
958         FileName const document_path(lyxrc.document_path);
959         if (document_path.exists() && document_path.isDirectory())
960                 package().document_dir() = document_path;
961
962         package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
963         if (package().temp_dir().empty()) {
964                 Alert::error(_("Could not create temporary directory"),
965                              bformat(_("Could not create a temporary directory in\n"
966                                                        "\"%1$s\"\n"
967                                                            "Make sure that this path exists and is writable and try again."),
968                                      from_utf8(lyxrc.tempdir_path)));
969                 // createLyXTmpDir() tries sufficiently hard to create a
970                 // usable temp dir, so the probability to come here is
971                 // close to zero. We therefore don't try to overcome this
972                 // problem with e.g. asking the user for a new path and
973                 // trying again but simply exit.
974                 return false;
975         }
976
977         LYXERR(Debug::INIT, "LyX tmp dir: `"
978                             << package().temp_dir().absFileName() << '\'');
979
980         LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
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 emergencyCleanup()
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         singleton_->pimpl_->buffer_list_.emergencyWriteAll();
999         if (use_gui) {
1000                 if (singleton_->pimpl_->lyx_server_)
1001                         singleton_->pimpl_->lyx_server_->emergencyCleanup();
1002                 singleton_->pimpl_->lyx_server_.reset();
1003                 singleton_->pimpl_->lyx_socket_.reset();
1004         }
1005 }
1006
1007
1008 bool LyX::queryUserLyXDir(bool explicit_userdir)
1009 {
1010         // Does user directory exist?
1011         FileName const sup = package().user_support();
1012         if (sup.exists() && sup.isDirectory()) {
1013                 first_start = false;
1014
1015                 return configFileNeedsUpdate("lyxrc.defaults")
1016                         || configFileNeedsUpdate("lyxmodules.lst")
1017                         || configFileNeedsUpdate("textclass.lst")
1018                         || configFileNeedsUpdate("packages.lst");
1019         }
1020
1021         first_start = !explicit_userdir;
1022
1023         // If the user specified explicitly a directory, ask whether
1024         // to create it. If the user says "no", then exit.
1025         if (explicit_userdir &&
1026             Alert::prompt(
1027                     _("Missing user LyX directory"),
1028                     bformat(_("You have specified a non-existent user "
1029                                            "LyX directory, %1$s.\n"
1030                                            "It is needed to keep your own configuration."),
1031                             from_utf8(package().user_support().absFileName())),
1032                     1, 0,
1033                     _("&Create directory"),
1034                     _("&Exit LyX"))) {
1035                 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1036                 earlyExit(EXIT_FAILURE);
1037         }
1038
1039         lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1040                           from_utf8(sup.absFileName()))) << endl;
1041
1042         if (!sup.createDirectory(0755)) {
1043                 // Failed, so let's exit.
1044                 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1045                        << endl;
1046                 earlyExit(EXIT_FAILURE);
1047         }
1048
1049         return true;
1050 }
1051
1052
1053 bool LyX::readRcFile(string const & name, bool check_format)
1054 {
1055         LYXERR(Debug::INIT, "About to read " << name << "... ");
1056
1057         FileName const lyxrc_path = libFileSearch(string(), name);
1058         if (lyxrc_path.empty()) {
1059                 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
1060                 // FIXME
1061                 // This was the previous logic, but can it be right??
1062                 return true;
1063         }
1064         LYXERR(Debug::INIT, "Found in " << lyxrc_path);
1065         bool const success = lyxrc.read(lyxrc_path, check_format);
1066         if (!success)
1067                 showFileError(name);
1068         return success;
1069 }
1070
1071 // Read the languages file `name'
1072 bool LyX::readLanguagesFile(string const & name)
1073 {
1074         LYXERR(Debug::INIT, "About to read " << name << "...");
1075
1076         FileName const lang_path = libFileSearch(string(), name);
1077         if (lang_path.empty()) {
1078                 showFileError(name);
1079                 return false;
1080         }
1081         languages.read(lang_path);
1082         return true;
1083 }
1084
1085
1086 // Read the encodings file `name'
1087 bool LyX::readEncodingsFile(string const & enc_name,
1088                             string const & symbols_name)
1089 {
1090         LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1091                             << symbols_name << "...");
1092
1093         FileName const symbols_path = libFileSearch(string(), symbols_name);
1094         if (symbols_path.empty()) {
1095                 showFileError(symbols_name);
1096                 return false;
1097         }
1098
1099         FileName const enc_path = libFileSearch(string(), enc_name);
1100         if (enc_path.empty()) {
1101                 showFileError(enc_name);
1102                 return false;
1103         }
1104         encodings.read(enc_path, symbols_path);
1105         return true;
1106 }
1107
1108
1109 namespace {
1110
1111 /// return the the number of arguments consumed
1112 typedef boost::function<int(string const &, string const &, string &)> cmd_helper;
1113
1114 int parse_dbg(string const & arg, string const &, string &)
1115 {
1116         if (arg.empty()) {
1117                 cout << to_utf8(_("List of supported debug flags:")) << endl;
1118                 Debug::showTags(cout);
1119                 exit(0);
1120         }
1121         lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1122
1123         lyxerr.setLevel(Debug::value(arg));
1124         Debug::showLevel(lyxerr, lyxerr.level());
1125         return 1;
1126 }
1127
1128
1129 int parse_help(string const &, string const &, string &)
1130 {
1131         cout <<
1132                 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1133                   "Command line switches (case sensitive):\n"
1134                   "\t-help              summarize LyX usage\n"
1135                   "\t-userdir dir       set user directory to dir\n"
1136                   "\t-sysdir dir        set system directory to dir\n"
1137                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
1138                   "\t-dbg feature[,feature]...\n"
1139                   "                  select the features to debug.\n"
1140                   "                  Type `lyx -dbg' to see the list of features\n"
1141                   "\t-x [--execute] command\n"
1142                   "                  where command is a lyx command.\n"
1143                   "\t-e [--export] fmt\n"
1144                   "                  where fmt is the export format of choice. Look in\n"
1145                   "                  Tools->Preferences->File Handling->File Formats->Short Name\n"
1146                   "                  to see which parameter (which differs from the format name\n"
1147                   "                  in the File->Export menu) should be passed.\n"
1148                   "                  Note that the order of -e and -x switches matters.\n"
1149                   "\t-E [--export-to] fmt filename\n"
1150                   "                  where fmt is the export format of choice (see --export),\n"
1151                   "                  and filename is the destination filename.\n"
1152                   "\t-i [--import] fmt file.xxx\n"
1153                   "                  where fmt is the import format of choice\n"
1154                   "                  and file.xxx is the file to be imported.\n"
1155                   "\t-f [--force-overwrite] what\n"
1156                   "                  where what is either `all', `main' or `none',\n"
1157                   "                  specifying whether all files, main file only, or no files,\n"
1158                   "                  respectively, are to be overwritten during a batch export.\n"
1159                   "                  Anything else is equivalent to `all', but is not consumed.\n"
1160                   "\t-n [--no-remote]\n"
1161                   "                  open documents in a new instance\n"
1162                   "\t-r [--remote]\n"
1163                   "                  open documents in an already running instance\n"
1164                   "                  (a working lyxpipe is needed)\n"
1165                   "\t-batch    execute commands without launching GUI and exit.\n"
1166                   "\t-version  summarize version and build info\n"
1167                                "Check the LyX man page for more details.")) << endl;
1168         exit(0);
1169         return 0;
1170 }
1171
1172
1173 int parse_version(string const &, string const &, string &)
1174 {
1175         cout << "LyX " << lyx_version
1176                << " (" << lyx_release_date << ")" << endl;
1177         if (string(lyx_git_commit_hash) != "none")
1178                 cout << to_utf8(_("  Git commit hash "))
1179                      << string(lyx_git_commit_hash).substr(0,8) << endl;
1180         cout << lyx_version_info << endl;
1181         exit(0);
1182         return 0;
1183 }
1184
1185
1186 int parse_sysdir(string const & arg, string const &, string &)
1187 {
1188         if (arg.empty()) {
1189                 Alert::error(_("No system directory"),
1190                         _("Missing directory for -sysdir switch"));
1191                 exit(1);
1192         }
1193         cl_system_support = arg;
1194         return 1;
1195 }
1196
1197
1198 int parse_userdir(string const & arg, string const &, string &)
1199 {
1200         if (arg.empty()) {
1201                 Alert::error(_("No user directory"),
1202                         _("Missing directory for -userdir switch"));
1203                 exit(1);
1204         }
1205         cl_user_support = arg;
1206         return 1;
1207 }
1208
1209
1210 int parse_execute(string const & arg, string const &, string & batch)
1211 {
1212         if (arg.empty()) {
1213                 Alert::error(_("Incomplete command"),
1214                         _("Missing command string after --execute switch"));
1215                 exit(1);
1216         }
1217         batch = arg;
1218         return 1;
1219 }
1220
1221
1222 int parse_export_to(string const & type, string const & output_file, string & batch)
1223 {
1224         if (type.empty()) {
1225                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1226                                          "--export-to switch")) << endl;
1227                 exit(1);
1228         }
1229         if (output_file.empty()) {
1230                 lyxerr << to_utf8(_("Missing destination filename after "
1231                                          "--export-to switch")) << endl;
1232                 exit(1);
1233         }
1234         batch = "buffer-export " + type + " " + output_file;
1235         use_gui = false;
1236         return 2;
1237 }
1238
1239
1240 int parse_export(string const & type, string const &, string & batch)
1241 {
1242         if (type.empty()) {
1243                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1244                                          "--export switch")) << endl;
1245                 exit(1);
1246         }
1247         batch = "buffer-export " + type;
1248         use_gui = false;
1249         return 1;
1250 }
1251
1252
1253 int parse_import(string const & type, string const & file, string & batch)
1254 {
1255         if (type.empty()) {
1256                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1257                                          "--import switch")) << endl;
1258                 exit(1);
1259         }
1260         if (file.empty()) {
1261                 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1262                 exit(1);
1263         }
1264         batch = "buffer-import " + type + ' ' + file;
1265         return 2;
1266 }
1267
1268
1269 int parse_geometry(string const & arg1, string const &, string &)
1270 {
1271         geometryArg = arg1;
1272         // don't remove "-geometry", it will be pruned out later in the
1273         // frontend if need be.
1274         return -1;
1275 }
1276
1277
1278 int parse_batch(string const &, string const &, string &)
1279 {
1280         use_gui = false;
1281         return 0;
1282 }
1283
1284
1285 int parse_noremote(string const &, string const &, string &)
1286 {
1287         run_mode = NEW_INSTANCE;
1288         return 0;
1289 }
1290
1291
1292 int parse_remote(string const &, string const &, string &)
1293 {
1294         run_mode = USE_REMOTE;
1295         return 0;
1296 }
1297
1298
1299 int parse_force(string const & arg, string const &, string &)
1300 {
1301         if (arg == "all") {
1302                 force_overwrite = ALL_FILES;
1303                 return 1;
1304         } else if (arg == "main") {
1305                 force_overwrite = MAIN_FILE;
1306                 return 1;
1307         } else if (arg == "none") {
1308                 force_overwrite = NO_FILES;
1309                 return 1;
1310         }
1311         force_overwrite = ALL_FILES;
1312         return 0;
1313 }
1314
1315
1316 } // namespace anon
1317
1318
1319 void LyX::easyParse(int & argc, char * argv[])
1320 {
1321         map<string, cmd_helper> cmdmap;
1322
1323         cmdmap["-dbg"] = parse_dbg;
1324         cmdmap["-help"] = parse_help;
1325         cmdmap["--help"] = parse_help;
1326         cmdmap["-version"] = parse_version;
1327         cmdmap["--version"] = parse_version;
1328         cmdmap["-sysdir"] = parse_sysdir;
1329         cmdmap["-userdir"] = parse_userdir;
1330         cmdmap["-x"] = parse_execute;
1331         cmdmap["--execute"] = parse_execute;
1332         cmdmap["-e"] = parse_export;
1333         cmdmap["--export"] = parse_export;
1334         cmdmap["-E"] = parse_export_to;
1335         cmdmap["--export-to"] = parse_export_to;
1336         cmdmap["-i"] = parse_import;
1337         cmdmap["--import"] = parse_import;
1338         cmdmap["-geometry"] = parse_geometry;
1339         cmdmap["-batch"] = parse_batch;
1340         cmdmap["-f"] = parse_force;
1341         cmdmap["--force-overwrite"] = parse_force;
1342         cmdmap["-n"] = parse_noremote;
1343         cmdmap["--no-remote"] = parse_noremote;
1344         cmdmap["-r"] = parse_remote;
1345         cmdmap["--remote"] = parse_remote;
1346
1347         for (int i = 1; i < argc; ++i) {
1348                 map<string, cmd_helper>::const_iterator it
1349                         = cmdmap.find(argv[i]);
1350
1351                 // don't complain if not found - may be parsed later
1352                 if (it == cmdmap.end())
1353                         continue;
1354
1355                 string const arg =
1356                         (i + 1 < argc) ? os::utf8_argv(i + 1) : string();
1357                 string const arg2 =
1358                         (i + 2 < argc) ? os::utf8_argv(i + 2) : string();
1359
1360                 string batch;
1361                 int const remove = 1 + it->second(arg, arg2, batch);
1362                 if (!batch.empty())
1363                         pimpl_->batch_commands.push_back(batch);
1364
1365                 // Now, remove used arguments by shifting
1366                 // the following ones remove places down.
1367                 if (remove > 0) {
1368                         os::remove_internal_args(i, remove);
1369                         argc -= remove;
1370                         for (int j = i; j < argc; ++j)
1371                                 argv[j] = argv[j + remove];
1372                         --i;
1373                 }
1374         }
1375 }
1376
1377
1378 FuncStatus getStatus(FuncRequest const & action)
1379 {
1380         LAPPERR(theApp());
1381         return theApp()->getStatus(action);
1382 }
1383
1384
1385 DispatchResult const & dispatch(FuncRequest const & action)
1386 {
1387         LAPPERR(theApp());
1388         return theApp()->dispatch(action);
1389 }
1390
1391
1392 void dispatch(FuncRequest const & action, DispatchResult & dr)
1393 {
1394         LAPPERR(theApp());
1395         theApp()->dispatch(action, dr);
1396 }
1397
1398
1399 vector<string> & theFilesToLoad()
1400 {
1401         LAPPERR(singleton_);
1402         return singleton_->pimpl_->files_to_load_;
1403 }
1404
1405
1406 BufferList & theBufferList()
1407 {
1408         LAPPERR(singleton_);
1409         return singleton_->pimpl_->buffer_list_;
1410 }
1411
1412
1413 Server & theServer()
1414 {
1415         // FIXME: this should not be use_gui dependent
1416         LWARNIF(use_gui);
1417         LAPPERR(singleton_);
1418         return *singleton_->pimpl_->lyx_server_.get();
1419 }
1420
1421
1422 ServerSocket & theServerSocket()
1423 {
1424         // FIXME: this should not be use_gui dependent
1425         LWARNIF(use_gui);
1426         LAPPERR(singleton_);
1427         return *singleton_->pimpl_->lyx_socket_.get();
1428 }
1429
1430
1431 KeyMap & theTopLevelKeymap()
1432 {
1433         LAPPERR(singleton_);
1434         return singleton_->pimpl_->toplevel_keymap_;
1435 }
1436
1437
1438 Converters & theConverters()
1439 {
1440         LAPPERR(singleton_);
1441         return  singleton_->pimpl_->converters_;
1442 }
1443
1444
1445 Converters & theSystemConverters()
1446 {
1447         LAPPERR(singleton_);
1448         return  singleton_->pimpl_->system_converters_;
1449 }
1450
1451
1452 Movers & theMovers()
1453 {
1454         LAPPERR(singleton_);
1455         return singleton_->pimpl_->movers_;
1456 }
1457
1458
1459 Mover const & getMover(string  const & fmt)
1460 {
1461         LAPPERR(singleton_);
1462         return singleton_->pimpl_->movers_(fmt);
1463 }
1464
1465
1466 void setMover(string const & fmt, string const & command)
1467 {
1468         LAPPERR(singleton_);
1469         singleton_->pimpl_->movers_.set(fmt, command);
1470 }
1471
1472
1473 Movers & theSystemMovers()
1474 {
1475         LAPPERR(singleton_);
1476         return singleton_->pimpl_->system_movers_;
1477 }
1478
1479
1480 Messages const & getMessages(string const & language)
1481 {
1482         LAPPERR(singleton_);
1483         return singleton_->messages(language);
1484 }
1485
1486
1487 Messages const & getGuiMessages()
1488 {
1489         LAPPERR(singleton_);
1490         return singleton_->messages(Messages::guiLanguage());
1491 }
1492
1493
1494 Session & theSession()
1495 {
1496         LAPPERR(singleton_);
1497         return *singleton_->pimpl_->session_.get();
1498 }
1499
1500
1501 LaTeXFonts & theLaTeXFonts()
1502 {
1503         LAPPERR(singleton_);
1504         if (!singleton_->pimpl_->latexfonts_)
1505                 singleton_->pimpl_->latexfonts_ = new LaTeXFonts;
1506         return *singleton_->pimpl_->latexfonts_;
1507 }
1508
1509
1510 CmdDef & theTopLevelCmdDef()
1511 {
1512         LAPPERR(singleton_);
1513         return singleton_->pimpl_->toplevel_cmddef_;
1514 }
1515
1516
1517 SpellChecker * theSpellChecker()
1518 {
1519         if (!singleton_->pimpl_->spell_checker_)
1520                 setSpellChecker();
1521         return singleton_->pimpl_->spell_checker_;
1522 }
1523
1524
1525 void setSpellChecker()
1526 {
1527         SpellChecker::ChangeNumber speller_change_number =singleton_->pimpl_->spell_checker_ ?
1528                 singleton_->pimpl_->spell_checker_->changeNumber() : 0;
1529
1530         if (lyxrc.spellchecker == "native") {
1531 #if defined(USE_MACOSX_PACKAGING)
1532                 if (!singleton_->pimpl_->apple_spell_checker_)
1533                         singleton_->pimpl_->apple_spell_checker_ = new AppleSpellChecker;
1534                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->apple_spell_checker_;
1535 #else
1536                 singleton_->pimpl_->spell_checker_ = 0;
1537 #endif
1538         } else if (lyxrc.spellchecker == "aspell") {
1539 #if defined(USE_ASPELL)
1540                 if (!singleton_->pimpl_->aspell_checker_)
1541                         singleton_->pimpl_->aspell_checker_ = new AspellChecker;
1542                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->aspell_checker_;
1543 #else
1544                 singleton_->pimpl_->spell_checker_ = 0;
1545 #endif
1546         } else if (lyxrc.spellchecker == "enchant") {
1547 #if defined(USE_ENCHANT)
1548                 if (!singleton_->pimpl_->enchant_checker_)
1549                         singleton_->pimpl_->enchant_checker_ = new EnchantChecker;
1550                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->enchant_checker_;
1551 #else
1552                 singleton_->pimpl_->spell_checker_ = 0;
1553 #endif
1554         } else if (lyxrc.spellchecker == "hunspell") {
1555 #if defined(USE_HUNSPELL)
1556                 if (!singleton_->pimpl_->hunspell_checker_)
1557                         singleton_->pimpl_->hunspell_checker_ = new HunspellChecker;
1558                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->hunspell_checker_;
1559 #else
1560                 singleton_->pimpl_->spell_checker_ = 0;
1561 #endif
1562         } else {
1563                 singleton_->pimpl_->spell_checker_ = 0;
1564         }
1565         if (singleton_->pimpl_->spell_checker_) {
1566                 singleton_->pimpl_->spell_checker_->changeNumber(speller_change_number);
1567                 singleton_->pimpl_->spell_checker_->advanceChangeNumber();
1568         }
1569 }
1570
1571 } // namespace lyx