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