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