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