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