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