]> git.lyx.org Git - lyx.git/blob - src/LyX.cpp
cmake cosmetics
[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         if (!pimpl_->buffer_list_.empty())
668                 view->setBuffer(pimpl_->buffer_list_.last());
669 }
670
671
672 LyXView * LyX::newLyXView()
673 {
674         if (!lyx::use_gui)
675                 return 0;
676
677         // determine windows size and position, from lyxrc and/or session
678         // initial geometry
679         unsigned int width = 690;
680         unsigned int height = 510;
681         // default icon size, will be overwritten by  stored session value
682         unsigned int iconSizeXY = 0;
683         int maximized = LyXView::NotMaximized;
684         // first try lyxrc
685         if (lyxrc.geometry_width != 0 && lyxrc.geometry_height != 0 ) {
686                 width = lyxrc.geometry_width;
687                 height = lyxrc.geometry_height;
688         }
689         // if lyxrc returns (0,0), then use session info
690         else {
691                 string val = session().sessionInfo().load("WindowWidth");
692                 if (!val.empty())
693                         width = convert<unsigned int>(val);
694                 val = session().sessionInfo().load("WindowHeight");
695                 if (!val.empty())
696                         height = convert<unsigned int>(val);
697                 val = session().sessionInfo().load("WindowMaximized");
698                 if (!val.empty())
699                         maximized = convert<int>(val);
700                 val = session().sessionInfo().load("IconSizeXY");
701                 if (!val.empty())
702                         iconSizeXY = convert<unsigned int>(val);
703         }
704
705         // if user wants to restore window position
706         int posx = -1;
707         int posy = -1;
708         if (lyxrc.geometry_xysaved) {
709                 string val = session().sessionInfo().load("WindowPosX");
710                 if (!val.empty())
711                         posx = convert<int>(val);
712                 val = session().sessionInfo().load("WindowPosY");
713                 if (!val.empty())
714                         posy = convert<int>(val);
715         }
716
717         if (!geometryArg.empty())
718         {
719                 width = 0;
720                 height = 0;
721         }
722
723         // create the main window
724         LyXView * view = &pimpl_->application_->createView(width, height, posx, posy, maximized, iconSizeXY, geometryArg);
725
726         return view;
727 }
728
729 /*
730 Signals and Windows
731 ===================
732 The SIGHUP signal does not exist on Windows and does not need to be handled.
733
734 Windows handles SIGFPE and SIGSEGV signals as expected.
735
736 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
737 cause a new thread to be spawned. This may well result in unexpected
738 behaviour by the single-threaded LyX.
739
740 SIGTERM signals will come only from another process actually sending
741 that signal using 'raise' in Windows' POSIX compatability layer. It will
742 not come from the general "terminate process" methods that everyone
743 actually uses (and which can't be trapped). Killing an app 'politely' on
744 Windows involves first sending a WM_CLOSE message, something that is
745 caught already by the Qt frontend.
746
747 For more information see:
748
749 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
750 ...signals are mostly useless on Windows for a variety of reasons that are
751 Windows specific...
752
753 'UNIX Application Migration Guide, Chapter 9'
754 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
755
756 'How To Terminate an Application "Cleanly" in Win32'
757 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
758 */
759 extern "C" {
760
761 static void error_handler(int err_sig)
762 {
763         // Throw away any signals other than the first one received.
764         static sig_atomic_t handling_error = false;
765         if (handling_error)
766                 return;
767         handling_error = true;
768
769         // We have received a signal indicating a fatal error, so
770         // try and save the data ASAP.
771         LyX::cref().emergencyCleanup();
772
773         // These lyxerr calls may or may not work:
774
775         // Signals are asynchronous, so the main program may be in a very
776         // fragile state when a signal is processed and thus while a signal
777         // handler function executes.
778         // In general, therefore, we should avoid performing any
779         // I/O operations or calling most library and system functions from
780         // signal handlers.
781
782         // This shouldn't matter here, however, as we've already invoked
783         // emergencyCleanup.
784         switch (err_sig) {
785 #ifdef SIGHUP
786         case SIGHUP:
787                 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
788                 break;
789 #endif
790         case SIGFPE:
791                 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
792                 break;
793         case SIGSEGV:
794                 lyxerr << "\nlyx: SIGSEGV signal caught\n"
795                           "Sorry, you have found a bug in LyX. "
796                           "Please read the bug-reporting instructions "
797                           "in Help->Introduction and send us a bug report, "
798                           "if necessary. Thanks !\nBye." << endl;
799                 break;
800         case SIGINT:
801         case SIGTERM:
802                 // no comments
803                 break;
804         }
805
806         // Deinstall the signal handlers
807 #ifdef SIGHUP
808         signal(SIGHUP, SIG_DFL);
809 #endif
810         signal(SIGINT, SIG_DFL);
811         signal(SIGFPE, SIG_DFL);
812         signal(SIGSEGV, SIG_DFL);
813         signal(SIGTERM, SIG_DFL);
814
815 #ifdef SIGHUP
816         if (err_sig == SIGSEGV ||
817             (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
818 #else
819         if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
820 #endif
821                 support::abort();
822         exit(0);
823 }
824
825 }
826
827
828 void LyX::printError(ErrorItem const & ei)
829 {
830         docstring tmp = _("LyX: ") + ei.error + char_type(':')
831                 + ei.description;
832         std::cerr << to_utf8(tmp) << std::endl;
833 }
834
835
836 void LyX::initGuiFont()
837 {
838         if (lyxrc.roman_font_name.empty())
839                 lyxrc.roman_font_name = pimpl_->application_->romanFontName();
840
841         if (lyxrc.sans_font_name.empty())
842                 lyxrc.sans_font_name = pimpl_->application_->sansFontName();
843
844         if (lyxrc.typewriter_font_name.empty())
845                 lyxrc.typewriter_font_name
846                         = pimpl_->application_->typewriterFontName();
847 }
848
849
850 bool LyX::init()
851 {
852 #ifdef SIGHUP
853         signal(SIGHUP, error_handler);
854 #endif
855         signal(SIGFPE, error_handler);
856         signal(SIGSEGV, error_handler);
857         signal(SIGINT, error_handler);
858         signal(SIGTERM, error_handler);
859         // SIGPIPE can be safely ignored.
860
861         lyxrc.tempdir_path = package().temp_dir().absFilename();
862         lyxrc.document_path = package().document_dir().absFilename();
863
864         if (lyxrc.template_path.empty()) {
865                 lyxrc.template_path = addPath(package().system_support().absFilename(),
866                                               "templates");
867         }
868
869         //
870         // Read configuration files
871         //
872
873         // This one may have been distributed along with LyX.
874         if (!readRcFile("lyxrc.dist"))
875                 return false;
876
877         // Set the language defined by the distributor.
878         //setGuiLanguage(lyxrc.gui_language);
879
880         // Set the PATH correctly.
881 #if !defined (USE_POSIX_PACKAGING)
882         // Add the directory containing the LyX executable to the path
883         // so that LyX can find things like tex2lyx.
884         if (package().build_support().empty())
885                 prependEnvPath("PATH", package().binary_dir().absFilename());
886 #endif
887         if (!lyxrc.path_prefix.empty())
888                 prependEnvPath("PATH", lyxrc.path_prefix);
889
890         // Check that user LyX directory is ok.
891         if (queryUserLyXDir(package().explicit_user_support()))
892                 reconfigureUserLyXDir();
893
894         // no need for a splash when there is no GUI
895         if (!use_gui) {
896                 first_start = false;
897         }
898
899         // This one is generated in user_support directory by lib/configure.py.
900         if (!readRcFile("lyxrc.defaults"))
901                 return false;
902
903         // Query the OS to know what formats are viewed natively
904         formats.setAutoOpen();
905
906         // Read lyxrc.dist again to be able to override viewer auto-detection.
907         readRcFile("lyxrc.dist");
908
909         system_lyxrc = lyxrc;
910         system_formats = formats;
911         pimpl_->system_converters_ = pimpl_->converters_;
912         pimpl_->system_movers_ = pimpl_->movers_;
913         system_lcolor = lcolor;
914
915         // This one is edited through the preferences dialog.
916         if (!readRcFile("preferences"))
917                 return false;
918
919         if (!readEncodingsFile("encodings", "unicodesymbols"))
920                 return false;
921         if (!readLanguagesFile("languages"))
922                 return false;
923
924         // Load the layouts
925         LYXERR(Debug::INIT) << "Reading layouts..." << endl;
926         if (!LyXSetStyle())
927                 return false;
928
929         if (use_gui) {
930                 // Set the language defined by the user.
931                 //setGuiLanguage(lyxrc.gui_language);
932
933                 // Set up bindings
934                 pimpl_->toplevel_keymap_.reset(new KeyMap);
935                 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
936                 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
937
938                 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
939
940                 // Read menus
941                 if (!readUIFile(lyxrc.ui_file))
942                         return false;
943         }
944
945         if (lyxerr.debugging(Debug::LYXRC))
946                 lyxrc.print();
947
948         os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
949         if (!lyxrc.path_prefix.empty())
950                 prependEnvPath("PATH", lyxrc.path_prefix);
951
952         FileName const document_path(lyxrc.document_path);
953         if (fs::exists(document_path.toFilesystemEncoding()) &&
954             fs::is_directory(document_path.toFilesystemEncoding()))
955                 package().document_dir() = document_path;
956
957         package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
958         if (package().temp_dir().empty()) {
959                 Alert::error(_("Could not create temporary directory"),
960                              bformat(_("Could not create a temporary directory in\n"
961                                                     "%1$s. Make sure that this\n"
962                                                     "path exists and is writable and try again."),
963                                      from_utf8(lyxrc.tempdir_path)));
964                 // createLyXTmpDir() tries sufficiently hard to create a
965                 // usable temp dir, so the probability to come here is
966                 // close to zero. We therefore don't try to overcome this
967                 // problem with e.g. asking the user for a new path and
968                 // trying again but simply exit.
969                 return false;
970         }
971
972         LYXERR(Debug::INIT) << "LyX tmp dir: `"
973                             << package().temp_dir().absFilename()
974                             << '\'' << endl;
975
976         LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
977         pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
978
979         // This must happen after package initialization and after lyxrc is
980         // read, therefore it can't be done by a static object.
981         ConverterCache::init();
982
983         return true;
984 }
985
986
987 void LyX::defaultKeyBindings(KeyMap  * kbmap)
988 {
989         kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
990         kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
991         kbmap->bind("Up", FuncRequest(LFUN_UP));
992         kbmap->bind("Down", FuncRequest(LFUN_DOWN));
993
994         kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
995         kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
996         kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
997         kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
998
999         kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
1000         kbmap->bind("End", FuncRequest(LFUN_LINE_END));
1001         kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
1002         kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
1003
1004         kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
1005         //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
1006
1007         kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
1008         kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
1009
1010         // kbmap->bindings to enable the use of the numeric keypad
1011         // e.g. Num Lock set
1012         //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
1013         //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
1014         kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
1015         //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
1016         //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
1017         //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
1018         //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
1019         //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
1020         //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
1021         //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
1022         //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
1023         //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
1024         //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
1025         //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
1026         //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
1027         //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
1028         kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
1029         kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
1030         kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
1031         kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
1032         kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
1033         kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
1034         kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
1035         kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
1036 }
1037
1038
1039 void LyX::emergencyCleanup() const
1040 {
1041         // what to do about tmpfiles is non-obvious. we would
1042         // like to delete any we find, but our lyxdir might
1043         // contain documents etc. which might be helpful on
1044         // a crash
1045
1046         pimpl_->buffer_list_.emergencyWriteAll();
1047         if (use_gui) {
1048                 if (pimpl_->lyx_server_)
1049                         pimpl_->lyx_server_->emergencyCleanup();
1050                 pimpl_->lyx_server_.reset();
1051                 pimpl_->lyx_socket_.reset();
1052         }
1053 }
1054
1055
1056 void LyX::deadKeyBindings(KeyMap * kbmap)
1057 {
1058         // bindKeyings for transparent handling of deadkeys
1059         // The keysyms are gotten from XFree86 X11R6
1060         kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1061         kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1062         kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1063         kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1064         kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1065         kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1066         kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1067         kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1068         kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1069         kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1070         // nothing with this name
1071         // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1072         kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1073         kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1074         // nothing with this name either...
1075         //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1076         kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1077         kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1078         kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1079 }
1080
1081
1082 namespace {
1083
1084 // return true if file does not exist or is older than configure.py.
1085 bool needsUpdate(string const & file)
1086 {
1087         // We cannot initialize configure_script directly because the package
1088         // is not initialized yet when  static objects are constructed.
1089         static string configure_script;
1090         static bool firstrun = true;
1091         if (firstrun) {
1092                 configure_script = FileName(addName(
1093                                 package().system_support().absFilename(),
1094                                 "configure.py")).toFilesystemEncoding();
1095                 firstrun = false;
1096         }
1097
1098         string const absfile = FileName(addName(
1099                 package().user_support().absFilename(), file)).toFilesystemEncoding();
1100         return (! fs::exists(absfile))
1101                 || (fs::last_write_time(configure_script)
1102                     > fs::last_write_time(absfile));
1103 }
1104
1105 }
1106
1107
1108 bool LyX::queryUserLyXDir(bool explicit_userdir)
1109 {
1110         // Does user directory exist?
1111         string const user_support =
1112                 package().user_support().toFilesystemEncoding();
1113         if (fs::exists(user_support) && fs::is_directory(user_support)) {
1114                 first_start = false;
1115
1116                 return needsUpdate("lyxrc.defaults")
1117                         || needsUpdate("textclass.lst")
1118                         || needsUpdate("packages.lst");
1119         }
1120
1121         first_start = !explicit_userdir;
1122
1123         // If the user specified explicitly a directory, ask whether
1124         // to create it. If the user says "no", then exit.
1125         if (explicit_userdir &&
1126             Alert::prompt(
1127                     _("Missing user LyX directory"),
1128                     bformat(_("You have specified a non-existent user "
1129                                            "LyX directory, %1$s.\n"
1130                                            "It is needed to keep your own configuration."),
1131                             from_utf8(package().user_support().absFilename())),
1132                     1, 0,
1133                     _("&Create directory"),
1134                     _("&Exit LyX"))) {
1135                 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1136                 earlyExit(EXIT_FAILURE);
1137         }
1138
1139         lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1140                           from_utf8(package().user_support().absFilename())))
1141                << endl;
1142
1143         if (!createDirectory(package().user_support(), 0755)) {
1144                 // Failed, so let's exit.
1145                 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1146                        << endl;
1147                 earlyExit(EXIT_FAILURE);
1148         }
1149
1150         return true;
1151 }
1152
1153
1154 bool LyX::readRcFile(string const & name)
1155 {
1156         LYXERR(Debug::INIT) << "About to read " << name << "... ";
1157
1158         FileName const lyxrc_path = libFileSearch(string(), name);
1159         if (!lyxrc_path.empty()) {
1160
1161                 LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
1162
1163                 if (lyxrc.read(lyxrc_path) < 0) {
1164                         showFileError(name);
1165                         return false;
1166                 }
1167         } else
1168                 LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
1169         return true;
1170
1171 }
1172
1173
1174 // Read the ui file `name'
1175 bool LyX::readUIFile(string const & name, bool include)
1176 {
1177         enum Uitags {
1178                 ui_menuset = 1,
1179                 ui_toolbars,
1180                 ui_toolbarset,
1181                 ui_include,
1182                 ui_last
1183         };
1184
1185         struct keyword_item uitags[ui_last - 1] = {
1186                 { "include", ui_include },
1187                 { "menuset", ui_menuset },
1188                 { "toolbars", ui_toolbars },
1189                 { "toolbarset", ui_toolbarset }
1190         };
1191
1192         // Ensure that a file is read only once (prevents include loops)
1193         static std::list<string> uifiles;
1194         std::list<string>::const_iterator it  = uifiles.begin();
1195         std::list<string>::const_iterator end = uifiles.end();
1196         it = std::find(it, end, name);
1197         if (it != end) {
1198                 LYXERR(Debug::INIT) << "UI file '" << name
1199                                     << "' has been read already. "
1200                                     << "Is this an include loop?"
1201                                     << endl;
1202                 return false;
1203         }
1204
1205         LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1206
1207
1208         FileName ui_path;
1209         if (include) {
1210                 ui_path = libFileSearch("ui", name, "inc");
1211                 if (ui_path.empty())
1212                         ui_path = libFileSearch("ui",
1213                                                 changeExtension(name, "inc"));
1214         }
1215         else
1216                 ui_path = libFileSearch("ui", name, "ui");
1217
1218         if (ui_path.empty()) {
1219                 LYXERR(Debug::INIT) << "Could not find " << name << endl;
1220                 showFileError(name);
1221                 return false;
1222         }
1223
1224         uifiles.push_back(name);
1225
1226         LYXERR(Debug::INIT) << "Found " << name
1227                             << " in " << ui_path << endl;
1228         Lexer lex(uitags, ui_last - 1);
1229         lex.setFile(ui_path);
1230         if (!lex.isOK()) {
1231                 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1232                        << endl;
1233         }
1234
1235         if (lyxerr.debugging(Debug::PARSER))
1236                 lex.printTable(lyxerr);
1237
1238         while (lex.isOK()) {
1239                 switch (lex.lex()) {
1240                 case ui_include: {
1241                         lex.next(true);
1242                         string const file = lex.getString();
1243                         if (!readUIFile(file, true))
1244                                 return false;
1245                         break;
1246                 }
1247                 case ui_menuset:
1248                         menubackend.read(lex);
1249                         break;
1250
1251                 case ui_toolbarset:
1252                         toolbarbackend.readToolbars(lex);
1253                         break;
1254
1255                 case ui_toolbars:
1256                         toolbarbackend.readToolbarSettings(lex);
1257                         break;
1258
1259                 default:
1260                         if (!rtrim(lex.getString()).empty())
1261                                 lex.printError("LyX::ReadUIFile: "
1262                                                "Unknown menu tag: `$$Token'");
1263                         break;
1264                 }
1265         }
1266         return true;
1267 }
1268
1269
1270 // Read the languages file `name'
1271 bool LyX::readLanguagesFile(string const & name)
1272 {
1273         LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1274
1275         FileName const lang_path = libFileSearch(string(), name);
1276         if (lang_path.empty()) {
1277                 showFileError(name);
1278                 return false;
1279         }
1280         languages.read(lang_path);
1281         return true;
1282 }
1283
1284
1285 // Read the encodings file `name'
1286 bool LyX::readEncodingsFile(string const & enc_name,
1287                             string const & symbols_name)
1288 {
1289         LYXERR(Debug::INIT) << "About to read " << enc_name << " and "
1290                             << symbols_name << "..." << endl;
1291
1292         FileName const symbols_path = libFileSearch(string(), symbols_name);
1293         if (symbols_path.empty()) {
1294                 showFileError(symbols_name);
1295                 return false;
1296         }
1297
1298         FileName const enc_path = libFileSearch(string(), enc_name);
1299         if (enc_path.empty()) {
1300                 showFileError(enc_name);
1301                 return false;
1302         }
1303         encodings.read(enc_path, symbols_path);
1304         return true;
1305 }
1306
1307
1308 namespace {
1309
1310 string batch;
1311
1312 /// return the the number of arguments consumed
1313 typedef boost::function<int(string const &, string const &)> cmd_helper;
1314
1315 int parse_dbg(string const & arg, string const &)
1316 {
1317         if (arg.empty()) {
1318                 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1319                 Debug::showTags(lyxerr);
1320                 exit(0);
1321         }
1322         lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1323
1324         lyxerr.level(Debug::value(arg));
1325         Debug::showLevel(lyxerr, lyxerr.level());
1326         return 1;
1327 }
1328
1329
1330 int parse_help(string const &, string const &)
1331 {
1332         lyxerr <<
1333                 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1334                   "Command line switches (case sensitive):\n"
1335                   "\t-help              summarize LyX usage\n"
1336                   "\t-userdir dir       set user directory to dir\n"
1337                   "\t-sysdir dir        set system directory to dir\n"
1338                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
1339                   "\t-dbg feature[,feature]...\n"
1340                   "                  select the features to debug.\n"
1341                   "                  Type `lyx -dbg' to see the list of features\n"
1342                   "\t-x [--execute] command\n"
1343                   "                  where command is a lyx command.\n"
1344                   "\t-e [--export] fmt\n"
1345                   "                  where fmt is the export format of choice.\n"
1346                   "\t-i [--import] fmt file.xxx\n"
1347                   "                  where fmt is the import format of choice\n"
1348                   "                  and file.xxx is the file to be imported.\n"
1349                   "\t-version        summarize version and build info\n"
1350                                "Check the LyX man page for more details.")) << endl;
1351         exit(0);
1352         return 0;
1353 }
1354
1355 int parse_version(string const &, string const &)
1356 {
1357         lyxerr << "LyX " << lyx_version
1358                << " (" << lyx_release_date << ")" << endl;
1359         lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1360
1361         lyxerr << lyx_version_info << endl;
1362         exit(0);
1363         return 0;
1364 }
1365
1366 int parse_sysdir(string const & arg, string const &)
1367 {
1368         if (arg.empty()) {
1369                 Alert::error(_("No system directory"),
1370                         _("Missing directory for -sysdir switch"));
1371                 exit(1);
1372         }
1373         cl_system_support = arg;
1374         return 1;
1375 }
1376
1377 int parse_userdir(string const & arg, string const &)
1378 {
1379         if (arg.empty()) {
1380                 Alert::error(_("No user directory"),
1381                         _("Missing directory for -userdir switch"));
1382                 exit(1);
1383         }
1384         cl_user_support = arg;
1385         return 1;
1386 }
1387
1388 int parse_execute(string const & arg, string const &)
1389 {
1390         if (arg.empty()) {
1391                 Alert::error(_("Incomplete command"),
1392                         _("Missing command string after --execute switch"));
1393                 exit(1);
1394         }
1395         batch = arg;
1396         return 1;
1397 }
1398
1399 int parse_export(string const & type, string const &)
1400 {
1401         if (type.empty()) {
1402                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1403                                          "--export switch")) << endl;
1404                 exit(1);
1405         }
1406         batch = "buffer-export " + type;
1407         use_gui = false;
1408         return 1;
1409 }
1410
1411 int parse_import(string const & type, string const & file)
1412 {
1413         if (type.empty()) {
1414                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1415                                          "--import switch")) << endl;
1416                 exit(1);
1417         }
1418         if (file.empty()) {
1419                 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1420                 exit(1);
1421         }
1422
1423         batch = "buffer-import " + type + ' ' + file;
1424         return 2;
1425 }
1426
1427 int parse_geometry(string const & arg1, string const &)
1428 {
1429         geometryArg = arg1;
1430 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1431         // remove also the arg
1432         return 1;
1433 #else
1434         // don't remove "-geometry"
1435         return -1;
1436 #endif
1437 }
1438
1439
1440 } // namespace anon
1441
1442
1443 void LyX::easyParse(int & argc, char * argv[])
1444 {
1445         std::map<string, cmd_helper> cmdmap;
1446
1447         cmdmap["-dbg"] = parse_dbg;
1448         cmdmap["-help"] = parse_help;
1449         cmdmap["--help"] = parse_help;
1450         cmdmap["-version"] = parse_version;
1451         cmdmap["--version"] = parse_version;
1452         cmdmap["-sysdir"] = parse_sysdir;
1453         cmdmap["-userdir"] = parse_userdir;
1454         cmdmap["-x"] = parse_execute;
1455         cmdmap["--execute"] = parse_execute;
1456         cmdmap["-e"] = parse_export;
1457         cmdmap["--export"] = parse_export;
1458         cmdmap["-i"] = parse_import;
1459         cmdmap["--import"] = parse_import;
1460         cmdmap["-geometry"] = parse_geometry;
1461
1462         for (int i = 1; i < argc; ++i) {
1463                 std::map<string, cmd_helper>::const_iterator it
1464                         = cmdmap.find(argv[i]);
1465
1466                 // don't complain if not found - may be parsed later
1467                 if (it == cmdmap.end())
1468                         continue;
1469
1470                 string const arg((i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string());
1471                 string const arg2((i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string());
1472
1473                 int const remove = 1 + it->second(arg, arg2);
1474
1475                 // Now, remove used arguments by shifting
1476                 // the following ones remove places down.
1477                 if (remove > 0) {
1478                         argc -= remove;
1479                         for (int j = i; j < argc; ++j)
1480                                 argv[j] = argv[j + remove];
1481                         --i;
1482                 }
1483         }
1484
1485         batch_command = batch;
1486 }
1487
1488
1489 FuncStatus getStatus(FuncRequest const & action)
1490 {
1491         return LyX::ref().lyxFunc().getStatus(action);
1492 }
1493
1494
1495 void dispatch(FuncRequest const & action)
1496 {
1497         LyX::ref().lyxFunc().dispatch(action);
1498 }
1499
1500
1501 BufferList & theBufferList()
1502 {
1503         return LyX::ref().bufferList();
1504 }
1505
1506
1507 LyXFunc & theLyXFunc()
1508 {
1509         return LyX::ref().lyxFunc();
1510 }
1511
1512
1513 Server & theServer()
1514 {
1515         // FIXME: this should not be use_gui dependent
1516         BOOST_ASSERT(use_gui);
1517         return LyX::ref().server();
1518 }
1519
1520
1521 ServerSocket & theServerSocket()
1522 {
1523         // FIXME: this should not be use_gui dependent
1524         BOOST_ASSERT(use_gui);
1525         return LyX::ref().socket();
1526 }
1527
1528
1529 KeyMap & theTopLevelKeymap()
1530 {
1531         BOOST_ASSERT(use_gui);
1532         return LyX::ref().topLevelKeymap();
1533 }
1534
1535
1536 Converters & theConverters()
1537 {
1538         return  LyX::ref().converters();
1539 }
1540
1541
1542 Converters & theSystemConverters()
1543 {
1544         return  LyX::ref().systemConverters();
1545 }
1546
1547
1548 Movers & theMovers()
1549 {
1550         return  LyX::ref().pimpl_->movers_;
1551 }
1552
1553
1554 Mover const & getMover(std::string  const & fmt)
1555 {
1556         return  LyX::ref().pimpl_->movers_(fmt);
1557 }
1558
1559
1560 void setMover(std::string const & fmt, std::string const & command)
1561 {
1562         LyX::ref().pimpl_->movers_.set(fmt, command);
1563 }
1564
1565
1566 Movers & theSystemMovers()
1567 {
1568         return  LyX::ref().pimpl_->system_movers_;
1569 }
1570
1571
1572 Messages & getMessages(std::string const & language)
1573 {
1574         return LyX::ref().getMessages(language);
1575 }
1576
1577
1578 Messages & getGuiMessages()
1579 {
1580         return LyX::ref().getGuiMessages();
1581 }
1582
1583 } // namespace lyx