]> git.lyx.org Git - lyx.git/blob - src/LyX.cpp
Fulfill promise to Andre: TextClass_ptr --> TextClassPtr.
[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 "CutAndPaste.h"
26 #include "debug.h"
27 #include "Encoding.h"
28 #include "ErrorList.h"
29 #include "Format.h"
30 #include "gettext.h"
31 #include "KeyMap.h"
32 #include "Language.h"
33 #include "Session.h"
34 #include "Color.h"
35 #include "callback.h"
36 #include "LyXAction.h"
37 #include "LyXFunc.h"
38 #include "Lexer.h"
39 #include "LyXRC.h"
40 #include "ModuleList.h"
41 #include "Server.h"
42 #include "ServerSocket.h"
43 #include "TextClassList.h"
44 #include "MenuBackend.h"
45 #include "Messages.h"
46 #include "Mover.h"
47 #include "ToolbarBackend.h"
48
49 #include "frontends/alert.h"
50 #include "frontends/Application.h"
51 #include "frontends/Dialogs.h"
52 #include "frontends/Gui.h"
53 #include "frontends/LyXView.h"
54
55 #include "support/environment.h"
56 #include "support/filetools.h"
57 #include "support/lyxlib.h"
58 #include "support/convert.h"
59 #include "support/ExceptionMessage.h"
60 #include "support/os.h"
61 #include "support/Package.h"
62 #include "support/Path.h"
63 #include "support/Systemcall.h"
64
65 #include <boost/bind.hpp>
66 #include <boost/filesystem/operations.hpp>
67
68 #include <algorithm>
69 #include <iostream>
70 #include <csignal>
71 #include <map>
72 #include <string>
73 #include <vector>
74
75 using std::endl;
76 using std::for_each;
77 using std::map;
78 using std::make_pair;
79 using std::string;
80 using std::vector;
81
82 #ifndef CXX_GLOBAL_CSTD
83 using std::exit;
84 using std::signal;
85 using std::system;
86 #endif
87
88 namespace fs = boost::filesystem;
89
90 namespace lyx {
91
92 using support::addName;
93 using support::addPath;
94 using support::bformat;
95 using support::changeExtension;
96 using support::createDirectory;
97 using support::createLyXTmpDir;
98 using support::destroyDir;
99 using support::FileName;
100 using support::fileSearch;
101 using support::getEnv;
102 using support::i18nLibFileSearch;
103 using support::libFileSearch;
104 using support::package;
105 using support::prependEnvPath;
106 using support::rtrim;
107 using support::Systemcall;
108 using frontend::LyXView;
109
110 namespace Alert = frontend::Alert;
111 namespace os = support::os;
112
113
114
115 /// are we using the GUI at all?
116 /**
117 * We default to true and this is changed to false when the export feature is used.
118 */
119 bool use_gui = true;
120
121
122 namespace {
123
124 // Filled with the command line arguments "foo" of "-sysdir foo" or
125 // "-userdir foo".
126 string cl_system_support;
127 string cl_user_support;
128
129 std::string geometryArg;
130
131 LyX * singleton_ = 0;
132
133 void showFileError(string const & error)
134 {
135         Alert::warning(_("Could not read configuration file"),
136                        bformat(_("Error while reading the configuration file\n%1$s.\n"
137                            "Please check your installation."), from_utf8(error)));
138 }
139
140
141 void reconfigureUserLyXDir()
142 {
143         string const configure_command = package().configure_command();
144
145         lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
146         support::Path p(package().user_support());
147         Systemcall one;
148         one.startscript(Systemcall::Wait, configure_command);
149         lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
150 }
151
152 } // namespace anon
153
154
155 /// The main application class private implementation.
156 struct LyX::Singletons
157 {
158         Singletons()
159         {
160                 // Set the default User Interface language as soon as possible.
161                 // The language used will be derived from the environment
162                 // variables.
163                 messages_["GUI"] = Messages();
164         }
165         /// our function handler
166         LyXFunc lyxfunc_;
167         ///
168         BufferList buffer_list_;
169         ///
170         boost::scoped_ptr<KeyMap> toplevel_keymap_;
171         ///
172         boost::scoped_ptr<Server> lyx_server_;
173         ///
174         boost::scoped_ptr<ServerSocket> lyx_socket_;
175         ///
176         boost::scoped_ptr<frontend::Application> application_;
177         /// lyx session, containing lastfiles, lastfilepos, and lastopened
178         boost::scoped_ptr<Session> session_;
179
180         /// Files to load at start.
181         vector<FileName> files_to_load_;
182
183         /// The messages translators.
184         map<string, Messages> messages_;
185
186         /// The file converters.
187         Converters converters_;
188
189         // The system converters copy after reading lyxrc.defaults.
190         Converters system_converters_;
191
192         ///
193         Movers movers_;
194
195         ///
196         Movers system_movers_;
197 };
198
199 ///
200 frontend::Application * theApp()
201 {
202         if (singleton_)
203                 return singleton_->pimpl_->application_.get();
204         else
205                 return 0;
206 }
207
208
209 LyX::~LyX()
210 {
211 }
212
213
214 LyX & LyX::ref()
215 {
216         BOOST_ASSERT(singleton_);
217         return *singleton_;
218 }
219
220
221 LyX const & LyX::cref()
222 {
223         BOOST_ASSERT(singleton_);
224         return *singleton_;
225 }
226
227
228 LyX::LyX()
229         : first_start(false)
230 {
231         singleton_ = this;
232         pimpl_.reset(new Singletons);
233 }
234
235
236 BufferList & LyX::bufferList()
237 {
238         return pimpl_->buffer_list_;
239 }
240
241
242 BufferList const & LyX::bufferList() const
243 {
244         return pimpl_->buffer_list_;
245 }
246
247
248 Session & LyX::session()
249 {
250         BOOST_ASSERT(pimpl_->session_.get());
251         return *pimpl_->session_.get();
252 }
253
254
255 Session const & LyX::session() const
256 {
257         BOOST_ASSERT(pimpl_->session_.get());
258         return *pimpl_->session_.get();
259 }
260
261
262 LyXFunc & LyX::lyxFunc()
263 {
264         return pimpl_->lyxfunc_;
265 }
266
267
268 LyXFunc const & LyX::lyxFunc() const
269 {
270         return pimpl_->lyxfunc_;
271 }
272
273
274 Server & LyX::server()
275 {
276         BOOST_ASSERT(pimpl_->lyx_server_.get());
277         return *pimpl_->lyx_server_.get();
278 }
279
280
281 Server const & LyX::server() const
282 {
283         BOOST_ASSERT(pimpl_->lyx_server_.get());
284         return *pimpl_->lyx_server_.get();
285 }
286
287
288 ServerSocket & LyX::socket()
289 {
290         BOOST_ASSERT(pimpl_->lyx_socket_.get());
291         return *pimpl_->lyx_socket_.get();
292 }
293
294
295 ServerSocket const & LyX::socket() const
296 {
297         BOOST_ASSERT(pimpl_->lyx_socket_.get());
298         return *pimpl_->lyx_socket_.get();
299 }
300
301
302 frontend::Application & LyX::application()
303 {
304         BOOST_ASSERT(pimpl_->application_.get());
305         return *pimpl_->application_.get();
306 }
307
308
309 frontend::Application const & LyX::application() const
310 {
311         BOOST_ASSERT(pimpl_->application_.get());
312         return *pimpl_->application_.get();
313 }
314
315
316 KeyMap & LyX::topLevelKeymap()
317 {
318         BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
319         return *pimpl_->toplevel_keymap_.get();
320 }
321
322
323 Converters & LyX::converters()
324 {
325         return pimpl_->converters_;
326 }
327
328
329 Converters & LyX::systemConverters()
330 {
331         return pimpl_->system_converters_;
332 }
333
334
335 KeyMap const & LyX::topLevelKeymap() const
336 {
337         BOOST_ASSERT(pimpl_->toplevel_keymap_.get());
338         return *pimpl_->toplevel_keymap_.get();
339 }
340
341
342 Messages & LyX::getMessages(std::string const & language)
343 {
344         map<string, Messages>::iterator it = pimpl_->messages_.find(language);
345
346         if (it != pimpl_->messages_.end())
347                 return it->second;
348
349         std::pair<map<string, Messages>::iterator, bool> result =
350                         pimpl_->messages_.insert(std::make_pair(language, Messages(language)));
351
352         BOOST_ASSERT(result.second);
353         return result.first->second;
354 }
355
356
357 Messages & LyX::getGuiMessages()
358 {
359         return pimpl_->messages_["GUI"];
360 }
361
362
363 void LyX::setGuiLanguage(std::string const & language)
364 {
365         pimpl_->messages_["GUI"] = Messages(language);
366 }
367
368
369 Buffer const * LyX::updateInset(Inset const * inset) const
370 {
371         if (quitting || !inset)
372                 return 0;
373
374         Buffer const * buffer_ptr = 0;
375         vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
376         vector<int>::const_iterator it = view_ids.begin();
377         vector<int>::const_iterator const end = view_ids.end();
378         for (; it != end; ++it) {
379                 Buffer const * ptr =
380                         pimpl_->application_->gui().view(*it).updateInset(inset);
381                 if (ptr)
382                         buffer_ptr = ptr;
383         }
384         return buffer_ptr;
385 }
386
387
388 void LyX::hideDialogs(std::string const & name, Inset * inset) const
389 {
390         if (quitting || !use_gui)
391                 return;
392
393         vector<int> const & view_ids = pimpl_->application_->gui().viewIds();
394         vector<int>::const_iterator it = view_ids.begin();
395         vector<int>::const_iterator const end = view_ids.end();
396         for (; it != end; ++it)
397                 pimpl_->application_->gui().view(*it).getDialogs().
398                         hide(name, inset);
399 }
400
401
402 int LyX::exec(int & argc, char * argv[])
403 {
404         // Here we need to parse the command line. At least
405         // we need to parse for "-dbg" and "-help"
406         easyParse(argc, argv);
407
408         try { support::init_package(to_utf8(from_local8bit(argv[0])),
409                               cl_system_support, cl_user_support,
410                               support::top_build_dir_is_one_level_up);
411         } catch (support::ExceptionMessage const & message) {
412                 if (message.type_ == support::ErrorException) {
413                         Alert::error(message.title_, message.details_);
414                         exit(1);
415                 } else if (message.type_ == support::WarningException) {
416                         Alert::warning(message.title_, message.details_);
417                 }
418         }
419
420         // Reinit the messages machinery in case package() knows
421         // something interesting about the locale directory.
422         Messages::init();
423
424         if (!use_gui) {
425                 // FIXME: create a ConsoleApplication
426                 int exit_status = init(argc, argv);
427                 if (exit_status) {
428                         prepareExit();
429                         return exit_status;
430                 }
431
432                 loadFiles();
433
434                 if (batch_command.empty() || pimpl_->buffer_list_.empty()) {
435                         prepareExit();
436                         return EXIT_SUCCESS;
437                 }
438
439                 BufferList::iterator begin = pimpl_->buffer_list_.begin();
440
441                 bool final_success = false;
442                 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
443                         Buffer * buf = *I;
444                         if (buf != buf->getMasterBuffer())
445                                 continue;
446                         bool success = false;
447                         buf->dispatch(batch_command, &success);
448                         final_success |= success;
449                 }
450                 prepareExit();
451                 return !final_success;
452         }
453
454         // Let the frontend parse and remove all arguments that it knows
455         pimpl_->application_.reset(createApplication(argc, argv));
456
457         initGuiFont();
458
459         // Parse and remove all known arguments in the LyX singleton
460         // Give an error for all remaining ones.
461         int exit_status = init(argc, argv);
462         if (exit_status) {
463                 // Kill the application object before exiting.
464                 pimpl_->application_.reset();
465                 use_gui = false;
466                 prepareExit();
467                 return exit_status;
468         }
469
470         // FIXME
471         /* Create a CoreApplication class that will provide the main event loop
472         * and the socket callback registering. With Qt4, only QtCore
473         * library would be needed.
474         * When this is done, a server_mode could be created and the following two
475         * line would be moved out from here.
476         */
477         // Note: socket callback must be registered after init(argc, argv)
478         // such that package().temp_dir() is properly initialized.
479         pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
480         pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
481                         FileName(package().temp_dir().absFilename() + "/lyxsocket")));
482
483         // Start the real execution loop.
484         exit_status = pimpl_->application_->exec();
485
486         prepareExit();
487
488         return exit_status;
489 }
490
491
492 void LyX::prepareExit()
493 {
494         // Clear the clipboard and selection stack:
495         cap::clearCutStack();
496         cap::clearSelection();
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         //...and the modules
929         moduleList.load();
930
931         if (use_gui) {
932                 // Set the language defined by the user.
933                 //setGuiLanguage(lyxrc.gui_language);
934
935                 // Set up bindings
936                 pimpl_->toplevel_keymap_.reset(new KeyMap);
937                 defaultKeyBindings(pimpl_->toplevel_keymap_.get());
938                 pimpl_->toplevel_keymap_->read(lyxrc.bind_file);
939
940                 pimpl_->lyxfunc_.initKeySequences(pimpl_->toplevel_keymap_.get());
941
942                 // Read menus
943                 if (!readUIFile(lyxrc.ui_file))
944                         return false;
945         }
946
947         if (lyxerr.debugging(Debug::LYXRC))
948                 lyxrc.print();
949
950         os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
951         if (!lyxrc.path_prefix.empty())
952                 prependEnvPath("PATH", lyxrc.path_prefix);
953
954         FileName const document_path(lyxrc.document_path);
955         if (fs::exists(document_path.toFilesystemEncoding()) &&
956             fs::is_directory(document_path.toFilesystemEncoding()))
957                 package().document_dir() = document_path;
958
959         package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
960         if (package().temp_dir().empty()) {
961                 Alert::error(_("Could not create temporary directory"),
962                              bformat(_("Could not create a temporary directory in\n"
963                                                     "%1$s. Make sure that this\n"
964                                                     "path exists and is writable and try again."),
965                                      from_utf8(lyxrc.tempdir_path)));
966                 // createLyXTmpDir() tries sufficiently hard to create a
967                 // usable temp dir, so the probability to come here is
968                 // close to zero. We therefore don't try to overcome this
969                 // problem with e.g. asking the user for a new path and
970                 // trying again but simply exit.
971                 return false;
972         }
973
974         LYXERR(Debug::INIT) << "LyX tmp dir: `"
975                             << package().temp_dir().absFilename()
976                             << '\'' << endl;
977
978         LYXERR(Debug::INIT) << "Reading session information '.lyx/session'..." << endl;
979         pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
980
981         // This must happen after package initialization and after lyxrc is
982         // read, therefore it can't be done by a static object.
983         ConverterCache::init();
984
985         return true;
986 }
987
988
989 void LyX::defaultKeyBindings(KeyMap  * kbmap)
990 {
991         kbmap->bind("Right", FuncRequest(LFUN_CHAR_FORWARD));
992         kbmap->bind("Left", FuncRequest(LFUN_CHAR_BACKWARD));
993         kbmap->bind("Up", FuncRequest(LFUN_UP));
994         kbmap->bind("Down", FuncRequest(LFUN_DOWN));
995
996         kbmap->bind("Tab", FuncRequest(LFUN_CELL_FORWARD));
997         kbmap->bind("C-Tab", FuncRequest(LFUN_CELL_SPLIT));
998         kbmap->bind("~S-ISO_Left_Tab", FuncRequest(LFUN_CELL_BACKWARD));
999         kbmap->bind("~S-BackTab", FuncRequest(LFUN_CELL_BACKWARD));
1000
1001         kbmap->bind("Home", FuncRequest(LFUN_LINE_BEGIN));
1002         kbmap->bind("End", FuncRequest(LFUN_LINE_END));
1003         kbmap->bind("Prior", FuncRequest(LFUN_SCREEN_UP));
1004         kbmap->bind("Next", FuncRequest(LFUN_SCREEN_DOWN));
1005
1006         kbmap->bind("Return", FuncRequest(LFUN_BREAK_PARAGRAPH));
1007         //kbmap->bind("~C-~S-~M-nobreakspace", FuncRequest(LFUN_PROTECTEDSPACE));
1008
1009         kbmap->bind("Delete", FuncRequest(LFUN_CHAR_DELETE_FORWARD));
1010         kbmap->bind("BackSpace", FuncRequest(LFUN_CHAR_DELETE_BACKWARD));
1011
1012         // kbmap->bindings to enable the use of the numeric keypad
1013         // e.g. Num Lock set
1014         //kbmap->bind("KP_0", FuncRequest(LFUN_SELF_INSERT));
1015         //kbmap->bind("KP_Decimal", FuncRequest(LFUN_SELF_INSERT));
1016         kbmap->bind("KP_Enter", FuncRequest(LFUN_BREAK_PARAGRAPH));
1017         //kbmap->bind("KP_1", FuncRequest(LFUN_SELF_INSERT));
1018         //kbmap->bind("KP_2", FuncRequest(LFUN_SELF_INSERT));
1019         //kbmap->bind("KP_3", FuncRequest(LFUN_SELF_INSERT));
1020         //kbmap->bind("KP_4", FuncRequest(LFUN_SELF_INSERT));
1021         //kbmap->bind("KP_5", FuncRequest(LFUN_SELF_INSERT));
1022         //kbmap->bind("KP_6", FuncRequest(LFUN_SELF_INSERT));
1023         //kbmap->bind("KP_Add", FuncRequest(LFUN_SELF_INSERT));
1024         //kbmap->bind("KP_7", FuncRequest(LFUN_SELF_INSERT));
1025         //kbmap->bind("KP_8", FuncRequest(LFUN_SELF_INSERT));
1026         //kbmap->bind("KP_9", FuncRequest(LFUN_SELF_INSERT));
1027         //kbmap->bind("KP_Divide", FuncRequest(LFUN_SELF_INSERT));
1028         //kbmap->bind("KP_Multiply", FuncRequest(LFUN_SELF_INSERT));
1029         //kbmap->bind("KP_Subtract", FuncRequest(LFUN_SELF_INSERT));
1030         kbmap->bind("KP_Right", FuncRequest(LFUN_CHAR_FORWARD));
1031         kbmap->bind("KP_Left", FuncRequest(LFUN_CHAR_BACKWARD));
1032         kbmap->bind("KP_Up", FuncRequest(LFUN_UP));
1033         kbmap->bind("KP_Down", FuncRequest(LFUN_DOWN));
1034         kbmap->bind("KP_Home", FuncRequest(LFUN_LINE_BEGIN));
1035         kbmap->bind("KP_End", FuncRequest(LFUN_LINE_END));
1036         kbmap->bind("KP_Prior", FuncRequest(LFUN_SCREEN_UP));
1037         kbmap->bind("KP_Next", FuncRequest(LFUN_SCREEN_DOWN));
1038 }
1039
1040
1041 void LyX::emergencyCleanup() const
1042 {
1043         // what to do about tmpfiles is non-obvious. we would
1044         // like to delete any we find, but our lyxdir might
1045         // contain documents etc. which might be helpful on
1046         // a crash
1047
1048         pimpl_->buffer_list_.emergencyWriteAll();
1049         if (use_gui) {
1050                 if (pimpl_->lyx_server_)
1051                         pimpl_->lyx_server_->emergencyCleanup();
1052                 pimpl_->lyx_server_.reset();
1053                 pimpl_->lyx_socket_.reset();
1054         }
1055 }
1056
1057
1058 void LyX::deadKeyBindings(KeyMap * kbmap)
1059 {
1060         // bindKeyings for transparent handling of deadkeys
1061         // The keysyms are gotten from XFree86 X11R6
1062         kbmap->bind("~C-~S-~M-dead_acute", FuncRequest(LFUN_ACCENT_ACUTE));
1063         kbmap->bind("~C-~S-~M-dead_breve", FuncRequest(LFUN_ACCENT_BREVE));
1064         kbmap->bind("~C-~S-~M-dead_caron", FuncRequest(LFUN_ACCENT_CARON));
1065         kbmap->bind("~C-~S-~M-dead_cedilla", FuncRequest(LFUN_ACCENT_CEDILLA));
1066         kbmap->bind("~C-~S-~M-dead_abovering", FuncRequest(LFUN_ACCENT_CIRCLE));
1067         kbmap->bind("~C-~S-~M-dead_circumflex", FuncRequest(LFUN_ACCENT_CIRCUMFLEX));
1068         kbmap->bind("~C-~S-~M-dead_abovedot", FuncRequest(LFUN_ACCENT_DOT));
1069         kbmap->bind("~C-~S-~M-dead_grave", FuncRequest(LFUN_ACCENT_GRAVE));
1070         kbmap->bind("~C-~S-~M-dead_doubleacute", FuncRequest(LFUN_ACCENT_HUNGARIAN_UMLAUT));
1071         kbmap->bind("~C-~S-~M-dead_macron", FuncRequest(LFUN_ACCENT_MACRON));
1072         // nothing with this name
1073         // kbmap->bind("~C-~S-~M-dead_special_caron", LFUN_ACCENT_SPECIAL_CARON);
1074         kbmap->bind("~C-~S-~M-dead_tilde", FuncRequest(LFUN_ACCENT_TILDE));
1075         kbmap->bind("~C-~S-~M-dead_diaeresis", FuncRequest(LFUN_ACCENT_UMLAUT));
1076         // nothing with this name either...
1077         //kbmap->bind("~C-~S-~M-dead_underbar", FuncRequest(LFUN_ACCENT_UNDERBAR));
1078         kbmap->bind("~C-~S-~M-dead_belowdot", FuncRequest(LFUN_ACCENT_UNDERDOT));
1079         kbmap->bind("~C-~S-~M-dead_tie", FuncRequest(LFUN_ACCENT_TIE));
1080         kbmap->bind("~C-~S-~M-dead_ogonek",FuncRequest(LFUN_ACCENT_OGONEK));
1081 }
1082
1083
1084 namespace {
1085
1086 // return true if file does not exist or is older than configure.py.
1087 bool needsUpdate(string const & file)
1088 {
1089         // We cannot initialize configure_script directly because the package
1090         // is not initialized yet when  static objects are constructed.
1091         static string configure_script;
1092         static bool firstrun = true;
1093         if (firstrun) {
1094                 configure_script = FileName(addName(
1095                                 package().system_support().absFilename(),
1096                                 "configure.py")).toFilesystemEncoding();
1097                 firstrun = false;
1098         }
1099
1100         string const absfile = FileName(addName(
1101                 package().user_support().absFilename(), file)).toFilesystemEncoding();
1102         return (! fs::exists(absfile))
1103                 || (fs::last_write_time(configure_script)
1104                     > fs::last_write_time(absfile));
1105 }
1106
1107 }
1108
1109
1110 bool LyX::queryUserLyXDir(bool explicit_userdir)
1111 {
1112         // Does user directory exist?
1113         string const user_support =
1114                 package().user_support().toFilesystemEncoding();
1115         if (fs::exists(user_support) && fs::is_directory(user_support)) {
1116                 first_start = false;
1117
1118                 return needsUpdate("lyxrc.defaults")
1119                         || needsUpdate("lyxmodules.lst")
1120                         || needsUpdate("textclass.lst")
1121                         || needsUpdate("packages.lst");
1122         }
1123
1124         first_start = !explicit_userdir;
1125
1126         // If the user specified explicitly a directory, ask whether
1127         // to create it. If the user says "no", then exit.
1128         if (explicit_userdir &&
1129             Alert::prompt(
1130                     _("Missing user LyX directory"),
1131                     bformat(_("You have specified a non-existent user "
1132                                            "LyX directory, %1$s.\n"
1133                                            "It is needed to keep your own configuration."),
1134                             from_utf8(package().user_support().absFilename())),
1135                     1, 0,
1136                     _("&Create directory"),
1137                     _("&Exit LyX"))) {
1138                 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1139                 earlyExit(EXIT_FAILURE);
1140         }
1141
1142         lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1143                           from_utf8(package().user_support().absFilename())))
1144                << endl;
1145
1146         if (!createDirectory(package().user_support(), 0755)) {
1147                 // Failed, so let's exit.
1148                 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1149                        << endl;
1150                 earlyExit(EXIT_FAILURE);
1151         }
1152
1153         return true;
1154 }
1155
1156
1157 bool LyX::readRcFile(string const & name)
1158 {
1159         LYXERR(Debug::INIT) << "About to read " << name << "... ";
1160
1161         FileName const lyxrc_path = libFileSearch(string(), name);
1162         if (!lyxrc_path.empty()) {
1163
1164                 LYXERR(Debug::INIT) << "Found in " << lyxrc_path << endl;
1165
1166                 if (lyxrc.read(lyxrc_path) < 0) {
1167                         showFileError(name);
1168                         return false;
1169                 }
1170         } else
1171                 LYXERR(Debug::INIT) << "Not found." << lyxrc_path << endl;
1172         return true;
1173
1174 }
1175
1176
1177 // Read the ui file `name'
1178 bool LyX::readUIFile(string const & name, bool include)
1179 {
1180         enum Uitags {
1181                 ui_menuset = 1,
1182                 ui_toolbars,
1183                 ui_toolbarset,
1184                 ui_include,
1185                 ui_last
1186         };
1187
1188         struct keyword_item uitags[ui_last - 1] = {
1189                 { "include", ui_include },
1190                 { "menuset", ui_menuset },
1191                 { "toolbars", ui_toolbars },
1192                 { "toolbarset", ui_toolbarset }
1193         };
1194
1195         // Ensure that a file is read only once (prevents include loops)
1196         static std::list<string> uifiles;
1197         std::list<string>::const_iterator it  = uifiles.begin();
1198         std::list<string>::const_iterator end = uifiles.end();
1199         it = std::find(it, end, name);
1200         if (it != end) {
1201                 LYXERR(Debug::INIT) << "UI file '" << name
1202                                     << "' has been read already. "
1203                                     << "Is this an include loop?"
1204                                     << endl;
1205                 return false;
1206         }
1207
1208         LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1209
1210
1211         FileName ui_path;
1212         if (include) {
1213                 ui_path = libFileSearch("ui", name, "inc");
1214                 if (ui_path.empty())
1215                         ui_path = libFileSearch("ui",
1216                                                 changeExtension(name, "inc"));
1217         }
1218         else
1219                 ui_path = libFileSearch("ui", name, "ui");
1220
1221         if (ui_path.empty()) {
1222                 LYXERR(Debug::INIT) << "Could not find " << name << endl;
1223                 showFileError(name);
1224                 return false;
1225         }
1226
1227         uifiles.push_back(name);
1228
1229         LYXERR(Debug::INIT) << "Found " << name
1230                             << " in " << ui_path << endl;
1231         Lexer lex(uitags, ui_last - 1);
1232         lex.setFile(ui_path);
1233         if (!lex.isOK()) {
1234                 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1235                        << endl;
1236         }
1237
1238         if (lyxerr.debugging(Debug::PARSER))
1239                 lex.printTable(lyxerr);
1240
1241         while (lex.isOK()) {
1242                 switch (lex.lex()) {
1243                 case ui_include: {
1244                         lex.next(true);
1245                         string const file = lex.getString();
1246                         if (!readUIFile(file, true))
1247                                 return false;
1248                         break;
1249                 }
1250                 case ui_menuset:
1251                         menubackend.read(lex);
1252                         break;
1253
1254                 case ui_toolbarset:
1255                         toolbarbackend.readToolbars(lex);
1256                         break;
1257
1258                 case ui_toolbars:
1259                         toolbarbackend.readToolbarSettings(lex);
1260                         break;
1261
1262                 default:
1263                         if (!rtrim(lex.getString()).empty())
1264                                 lex.printError("LyX::ReadUIFile: "
1265                                                "Unknown menu tag: `$$Token'");
1266                         break;
1267                 }
1268         }
1269         return true;
1270 }
1271
1272
1273 // Read the languages file `name'
1274 bool LyX::readLanguagesFile(string const & name)
1275 {
1276         LYXERR(Debug::INIT) << "About to read " << name << "..." << endl;
1277
1278         FileName const lang_path = libFileSearch(string(), name);
1279         if (lang_path.empty()) {
1280                 showFileError(name);
1281                 return false;
1282         }
1283         languages.read(lang_path);
1284         return true;
1285 }
1286
1287
1288 // Read the encodings file `name'
1289 bool LyX::readEncodingsFile(string const & enc_name,
1290                             string const & symbols_name)
1291 {
1292         LYXERR(Debug::INIT) << "About to read " << enc_name << " and "
1293                             << symbols_name << "..." << endl;
1294
1295         FileName const symbols_path = libFileSearch(string(), symbols_name);
1296         if (symbols_path.empty()) {
1297                 showFileError(symbols_name);
1298                 return false;
1299         }
1300
1301         FileName const enc_path = libFileSearch(string(), enc_name);
1302         if (enc_path.empty()) {
1303                 showFileError(enc_name);
1304                 return false;
1305         }
1306         encodings.read(enc_path, symbols_path);
1307         return true;
1308 }
1309
1310
1311 namespace {
1312
1313 string batch;
1314
1315 /// return the the number of arguments consumed
1316 typedef boost::function<int(string const &, string const &)> cmd_helper;
1317
1318 int parse_dbg(string const & arg, string const &)
1319 {
1320         if (arg.empty()) {
1321                 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1322                 Debug::showTags(lyxerr);
1323                 exit(0);
1324         }
1325         lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1326
1327         lyxerr.level(Debug::value(arg));
1328         Debug::showLevel(lyxerr, lyxerr.level());
1329         return 1;
1330 }
1331
1332
1333 int parse_help(string const &, string const &)
1334 {
1335         lyxerr <<
1336                 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1337                   "Command line switches (case sensitive):\n"
1338                   "\t-help              summarize LyX usage\n"
1339                   "\t-userdir dir       set user directory to dir\n"
1340                   "\t-sysdir dir        set system directory to dir\n"
1341                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
1342                   "\t-dbg feature[,feature]...\n"
1343                   "                  select the features to debug.\n"
1344                   "                  Type `lyx -dbg' to see the list of features\n"
1345                   "\t-x [--execute] command\n"
1346                   "                  where command is a lyx command.\n"
1347                   "\t-e [--export] fmt\n"
1348                   "                  where fmt is the export format of choice.\n"
1349                   "\t-i [--import] fmt file.xxx\n"
1350                   "                  where fmt is the import format of choice\n"
1351                   "                  and file.xxx is the file to be imported.\n"
1352                   "\t-version        summarize version and build info\n"
1353                                "Check the LyX man page for more details.")) << endl;
1354         exit(0);
1355         return 0;
1356 }
1357
1358 int parse_version(string const &, string const &)
1359 {
1360         lyxerr << "LyX " << lyx_version
1361                << " (" << lyx_release_date << ")" << endl;
1362         lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1363
1364         lyxerr << lyx_version_info << endl;
1365         exit(0);
1366         return 0;
1367 }
1368
1369 int parse_sysdir(string const & arg, string const &)
1370 {
1371         if (arg.empty()) {
1372                 Alert::error(_("No system directory"),
1373                         _("Missing directory for -sysdir switch"));
1374                 exit(1);
1375         }
1376         cl_system_support = arg;
1377         return 1;
1378 }
1379
1380 int parse_userdir(string const & arg, string const &)
1381 {
1382         if (arg.empty()) {
1383                 Alert::error(_("No user directory"),
1384                         _("Missing directory for -userdir switch"));
1385                 exit(1);
1386         }
1387         cl_user_support = arg;
1388         return 1;
1389 }
1390
1391 int parse_execute(string const & arg, string const &)
1392 {
1393         if (arg.empty()) {
1394                 Alert::error(_("Incomplete command"),
1395                         _("Missing command string after --execute switch"));
1396                 exit(1);
1397         }
1398         batch = arg;
1399         return 1;
1400 }
1401
1402 int parse_export(string const & type, string const &)
1403 {
1404         if (type.empty()) {
1405                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1406                                          "--export switch")) << endl;
1407                 exit(1);
1408         }
1409         batch = "buffer-export " + type;
1410         use_gui = false;
1411         return 1;
1412 }
1413
1414 int parse_import(string const & type, string const & file)
1415 {
1416         if (type.empty()) {
1417                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1418                                          "--import switch")) << endl;
1419                 exit(1);
1420         }
1421         if (file.empty()) {
1422                 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1423                 exit(1);
1424         }
1425
1426         batch = "buffer-import " + type + ' ' + file;
1427         return 2;
1428 }
1429
1430 int parse_geometry(string const & arg1, string const &)
1431 {
1432         geometryArg = arg1;
1433 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1434         // remove also the arg
1435         return 1;
1436 #else
1437         // don't remove "-geometry"
1438         return -1;
1439 #endif
1440 }
1441
1442
1443 } // namespace anon
1444
1445
1446 void LyX::easyParse(int & argc, char * argv[])
1447 {
1448         std::map<string, cmd_helper> cmdmap;
1449
1450         cmdmap["-dbg"] = parse_dbg;
1451         cmdmap["-help"] = parse_help;
1452         cmdmap["--help"] = parse_help;
1453         cmdmap["-version"] = parse_version;
1454         cmdmap["--version"] = parse_version;
1455         cmdmap["-sysdir"] = parse_sysdir;
1456         cmdmap["-userdir"] = parse_userdir;
1457         cmdmap["-x"] = parse_execute;
1458         cmdmap["--execute"] = parse_execute;
1459         cmdmap["-e"] = parse_export;
1460         cmdmap["--export"] = parse_export;
1461         cmdmap["-i"] = parse_import;
1462         cmdmap["--import"] = parse_import;
1463         cmdmap["-geometry"] = parse_geometry;
1464
1465         for (int i = 1; i < argc; ++i) {
1466                 std::map<string, cmd_helper>::const_iterator it
1467                         = cmdmap.find(argv[i]);
1468
1469                 // don't complain if not found - may be parsed later
1470                 if (it == cmdmap.end())
1471                         continue;
1472
1473                 string const arg((i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string());
1474                 string const arg2((i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string());
1475
1476                 int const remove = 1 + it->second(arg, arg2);
1477
1478                 // Now, remove used arguments by shifting
1479                 // the following ones remove places down.
1480                 if (remove > 0) {
1481                         argc -= remove;
1482                         for (int j = i; j < argc; ++j)
1483                                 argv[j] = argv[j + remove];
1484                         --i;
1485                 }
1486         }
1487
1488         batch_command = batch;
1489 }
1490
1491
1492 FuncStatus getStatus(FuncRequest const & action)
1493 {
1494         return LyX::ref().lyxFunc().getStatus(action);
1495 }
1496
1497
1498 void dispatch(FuncRequest const & action)
1499 {
1500         LyX::ref().lyxFunc().dispatch(action);
1501 }
1502
1503
1504 BufferList & theBufferList()
1505 {
1506         return LyX::ref().bufferList();
1507 }
1508
1509
1510 LyXFunc & theLyXFunc()
1511 {
1512         return LyX::ref().lyxFunc();
1513 }
1514
1515
1516 Server & theServer()
1517 {
1518         // FIXME: this should not be use_gui dependent
1519         BOOST_ASSERT(use_gui);
1520         return LyX::ref().server();
1521 }
1522
1523
1524 ServerSocket & theServerSocket()
1525 {
1526         // FIXME: this should not be use_gui dependent
1527         BOOST_ASSERT(use_gui);
1528         return LyX::ref().socket();
1529 }
1530
1531
1532 KeyMap & theTopLevelKeymap()
1533 {
1534         BOOST_ASSERT(use_gui);
1535         return LyX::ref().topLevelKeymap();
1536 }
1537
1538
1539 Converters & theConverters()
1540 {
1541         return  LyX::ref().converters();
1542 }
1543
1544
1545 Converters & theSystemConverters()
1546 {
1547         return  LyX::ref().systemConverters();
1548 }
1549
1550
1551 Movers & theMovers()
1552 {
1553         return  LyX::ref().pimpl_->movers_;
1554 }
1555
1556
1557 Mover const & getMover(std::string  const & fmt)
1558 {
1559         return  LyX::ref().pimpl_->movers_(fmt);
1560 }
1561
1562
1563 void setMover(std::string const & fmt, std::string const & command)
1564 {
1565         LyX::ref().pimpl_->movers_.set(fmt, command);
1566 }
1567
1568
1569 Movers & theSystemMovers()
1570 {
1571         return  LyX::ref().pimpl_->system_movers_;
1572 }
1573
1574
1575 Messages & getMessages(std::string const & language)
1576 {
1577         return LyX::ref().getMessages(language);
1578 }
1579
1580
1581 Messages & getGuiMessages()
1582 {
1583         return LyX::ref().getGuiMessages();
1584 }
1585
1586 } // namespace lyx