]> git.lyx.org Git - lyx.git/blob - src/lyx_main.C
d7c00d7bad4fcc79c4bf3d6f71480a73650d507b
[lyx.git] / src / lyx_main.C
1 /* This file is part of
2 * ======================================================
3
4 *           LyX, The Document Processor
5 *        
6 *           Copyright (C) 1995 Matthias Ettrich
7 *           Copyright (C) 1995-1998 The LyX Team.
8 *
9 *======================================================*/
10
11 #include <config.h>
12
13 //      $Id: lyx_main.C,v 1.1 1999/09/27 18:44:37 larsbj Exp $  
14
15 #if !defined(lint) && !defined(WITH_WARNINGS)
16 static char vcid[] = "$Id: lyx_main.C,v 1.1 1999/09/27 18:44:37 larsbj Exp $";
17 #endif /* lint */
18
19 #include <stdlib.h>
20 #include <signal.h>
21
22 #include "version.h"
23 #include "lyx_main.h"
24 #include "lyx_gui.h"
25 #include "lyx_gui_misc.h"
26 #include "lyxrc.h"
27 #include "pathstack.h"
28 #include "filetools.h"
29 #include "bufferlist.h"
30 #include "error.h"
31 #include "FileInfo.h"
32 #include "lastfiles.h"
33 #include "intl.h"
34 #include "lyxserver.h"
35 #include "layout.h"
36 #include "gettext.h"
37
38 extern void LoadLyXFile(LString const &);
39
40 LString system_lyxdir;
41 LString build_lyxdir;
42 LString system_tempdir;
43 LString user_lyxdir;    // Default $HOME/.lyx
44
45 // Should this be kept global? Asger says Yes.
46 Error lyxerr;
47
48 LastFiles *lastfiles;
49 LyXRC *lyxrc;
50
51 // This is the global bufferlist object
52 BufferList bufferlist;
53
54 LyXServer *lyxserver = 0;
55 // this should be static, but I need it in buffer.C
56 bool finished = false;  // flag, that we are quitting the program
57
58 // convenient to have it here.
59 kb_keymap *toplevel_keymap;
60
61 // from spellchecker.C
62 #if 0
63 extern void sigchldhandler(int sig);
64 #endif
65
66 LyX::LyX(int *argc, char *argv[])
67 {
68         // Prevent crash with --help
69         lyxGUI = 0;
70         lastfiles = 0;
71
72         // Here we need to parse the command line. At least
73         // we need to parse for "-dbg" and "-help"
74         bool gui = easyParse(argc, argv);
75
76         // Global bindings (this must be done as early as possible.) (Lgb)
77         toplevel_keymap = new kb_keymap;
78
79         lyxerr.debug("Initializing lyxrc");
80         lyxrc = new LyXRC;
81
82         // Make the GUI object, and let it take care of the
83         // command line arguments that concerns it.
84         lyxerr.debug("Initializing LyXGUI...");
85         lyxGUI = new LyXGUI(this, argc, argv, gui);
86         lyxerr.debug("Initializing LyXGUI...done");
87
88         // Initialization of LyX (reads lyxrc and more)
89         lyxerr.debug("Initializing LyX::init...");
90         init(argc, argv);
91         lyxerr.debug("Initializing LyX::init...done");
92
93         lyxGUI->init();
94
95         // Load the files specified in the command line.
96         // Now the GUI and LyX have taken care of their arguments, so
97         // the only thing left on the command line should be
98         // filenames.
99         if ((*argc)==2) 
100                 lyxerr.debug("Opening document...");
101         else if ((*argc)>2)
102                 lyxerr.debug("Opening documents...");
103
104         Buffer *last_loaded = NULL;
105
106         for (int argi = (*argc) - 1; argi >= 1; argi--) {
107                 Buffer * loadb = bufferlist.loadLyXFile(argv[argi]);
108                 if (loadb != 0) {
109                         last_loaded = loadb;
110                 }
111         }
112
113         if (first_start) {
114                 LString splash = i18nLibFileSearch("examples", "splash.lyx");
115                 lyxerr.debug("Opening splash document "+splash+"...");
116                 Buffer * loadb = bufferlist.loadLyXFile(splash);
117                 if (loadb != 0) {
118                         last_loaded = loadb;
119                 }
120         }
121
122         if (last_loaded != NULL) {
123                 lyxerr.debug("Yes we loaded some files.");
124                 lyxGUI->regBuf(last_loaded);
125         }
126         
127         // Let the ball begin...
128         lyxGUI->runTime();
129 }
130
131
132 // A destructor is always necessary  (asierra-970604)
133 LyX::~LyX()
134 {
135         if (lastfiles)
136                 delete lastfiles;
137
138         if (lyxGUI)
139                 delete lyxGUI;
140 }
141
142
143 extern "C" void error_handler(int err_sig);
144
145 void LyX::init(int */*argc*/, char **argv)
146 {
147         // Install the signal handlers
148         signal(SIGHUP, error_handler);
149         signal(SIGFPE, error_handler);
150         signal(SIGSEGV, error_handler);
151         signal(SIGINT, error_handler);
152         signal(SIGTERM, error_handler);
153
154 #if 0
155         // Install the SIGCHLD handler
156         act_.sa_handler = sigchldhandler;
157         //act_.sa_mask = SIGCHLD;
158         act_.sa_flags = 0;
159         //act_.sa_flags = SA_RESTART; //perhaps
160         sigaction(SIGCHLD, &act_, NULL);
161 #endif
162         //
163         // Determine path of binary
164         //
165
166         LString fullbinpath, binpath = argv[0];
167         binpath.subst('\\','/');
168         LString binname = OnlyFilename(argv[0]);
169         // Sorry for system specific code. (SMiyata)
170         if (binname.suffixIs(".exe")) binname.substring(0,binname.length()-5);
171         
172         binpath = ExpandPath(binpath); // This expands ./ and ~/
173         
174         if (!AbsolutePath(binpath)) {
175                 LString binsearchpath = getEnvPath("PATH");
176                 binsearchpath += ";."; // This will make "src/lyx" work always :-)
177                 binpath = FileOpenSearch(binsearchpath, argv[0]);
178         }
179
180         fullbinpath = binpath;
181         binpath = MakeAbsPath(OnlyPath(binpath));
182
183         if (binpath.empty()) {
184                 lyxerr.print(_("Warning: could not determine path of binary."));
185                 lyxerr.print(_("If you have problems, try starting LyX with an absolute path."));
186         }
187         lyxerr.debug("Path of binary: " + binpath);
188
189         //
190         // Determine system directory.
191         //
192
193         // Directories are searched in this order:
194         // 1) -sysdir command line parameter
195         // 2) LYX_DIR_10x environment variable
196         // 3) Maybe <path of binary>/TOP_SRCDIR/lib
197         // 4) <path of binary>/../share/<name of binary>/
198         // 4a) repeat 4 after following the Symlink if <path of
199         //     binary> is a symbolic link.
200         // 5) hardcoded lyx_dir
201         // The directory is checked for the presence of the file
202         // "chkconfig.ltx", and if that is present, the directory
203         // is accepted as the system directory.
204         // If no chkconfig.ltx file is found, a warning is given,
205         // and the hardcoded lyx_dir is used.
206
207         // If we had a command line switch, system_lyxdir is already set
208         LString searchpath = MakeAbsPath(system_lyxdir) + ';';
209
210         // LYX_DIR_10x environment variable
211         LString lyxdir = getEnvPath("LYX_DIR_10x");
212         
213         if (!lyxdir.empty()) {
214                 lyxerr.debug("LYX_DIR_10x: " + lyxdir, Error::INIT);
215                 searchpath += lyxdir + ';';
216         }
217
218         // <path of binary>/TOP_SRCDIR/lib
219         build_lyxdir = MakeAbsPath("../lib", binpath);
220         if (!FileSearch(build_lyxdir, "lyxrc.defaults").empty()) {
221                 searchpath += MakeAbsPath(AddPath(TOP_SRCDIR, "lib"),
222                                           binpath) + ';';
223                 lyxerr.debug("Checking whether LyX is run in "
224                               "place... yes", Error::INIT);
225         } else {
226                 lyxerr.debug("Checking whether LyX is run in place... no",
227                               Error::INIT);
228                 build_lyxdir.clean();
229         }
230
231
232         bool FollowLink;
233         do {
234           // Path of binary/../share/name of binary/
235                 searchpath += NormalizePath(AddPath(binpath, "../share/") + 
236                       OnlyFilename(binname)) + ';';
237
238           // Follow Symlinks
239                 FileInfo file(fullbinpath,true);
240                 FollowLink = file.isLink();
241                 if (FollowLink) {
242                         LString Link;
243                         if (LyXReadLink(fullbinpath,Link)) {
244                                 fullbinpath = Link;
245                                 binpath = MakeAbsPath(OnlyPath(fullbinpath));
246                         }
247                         else {
248                                 FollowLink = false;
249                         }
250                 }
251         } while (FollowLink);
252
253         // Hardcoded dir
254         searchpath += LYX_DIR;
255
256         // If debugging, show complete search path
257         lyxerr.debug("System directory search path: "+searchpath, Error::INIT);
258
259         LString const filename = "chkconfig.ltx";
260         LString temp = FileOpenSearch(searchpath, filename, LString());
261         system_lyxdir = OnlyPath(temp);
262
263         // Reduce "path/../path" stuff out of system directory
264         system_lyxdir = NormalizePath(system_lyxdir);
265
266         bool path_shown = false;
267
268         // Warn if environment variable is set, but unusable
269         if (!lyxdir.empty()) {
270                 if (system_lyxdir != NormalizePath(lyxdir)) {
271                         lyxerr.print(_("LYX_DIR_10x environment variable no good."));
272                         lyxerr.print(_("System directory set to: ") 
273                                      + system_lyxdir);
274                         path_shown = true;
275                 }
276         }
277
278         // Warn the user if we couldn't find "chkconfig.ltx"
279         if (system_lyxdir.empty()) {
280                 lyxerr.print(_("LyX Warning! Couldn't determine system directory."));
281                 lyxerr.print(_("Try the '-sysdir' command line parameter or"));
282                 lyxerr.print(_("set the environment variable LYX_DIR_10x to the "
283                               "LyX system directory"));
284                 lyxerr.print(_("containing the file `chkconfig.ltx'."));
285                 if (!path_shown)
286                         lyxerr.print(_("Using built-in default ") 
287                                      + LString(LYX_DIR) + _(" but expect problems."));
288                 else
289                         lyxerr.print(_("Expect problems."));
290                 system_lyxdir = LYX_DIR;
291                 path_shown = true;
292         }
293
294         // Report the system directory if debugging is on
295         if (!path_shown)
296                 lyxerr.debug("System directory: '" + system_lyxdir + '\'', 
297                               Error::INIT);
298
299         //
300         // Determine user lyx-dir
301         //
302         
303         user_lyxdir = AddPath(getEnvPath("HOME"), LString('.')+LYX_NAME);
304         lyxerr.debug("User LyX directory: '" 
305                      + user_lyxdir + '\'', Error::INIT);
306
307         // Check that user LyX directory is ok.
308         queryUserLyXDir();
309
310         //
311         // Load the layouts first
312         //
313
314         lyxerr.debug("Reading layouts...", Error::INIT);
315         LyXSetStyle();
316
317         //
318         // Shine up lyxrc defaults
319         //
320
321         // Default template path: system_dir/templates
322         if (lyxrc->template_path.empty()){
323                 lyxrc->template_path = AddPath(system_lyxdir, "templates");
324         }
325    
326         // Default lastfiles file: $HOME/.lyx/lastfiles
327         if (lyxrc->lastfiles.empty()){
328                 lyxrc->lastfiles = AddName(user_lyxdir, "lastfiles");
329         }
330
331         // Calculate screen dpi as average of x-DPI and y-DPI:
332         Screen * scr=(DefaultScreenOfDisplay(fl_get_display()));
333         lyxrc->dpi = ((HeightOfScreen(scr)* 25.4 / HeightMMOfScreen(scr)) +
334                       (WidthOfScreen(scr)* 25.4 / WidthMMOfScreen(scr))) / 2;
335         lyxerr.debug(LString("DPI setting detected to be ") + 
336                       int(lyxrc->dpi+0.5));
337
338         //
339         // Read configuration files
340         //
341
342         ReadRcFile("lyxrc.defaults");
343         ReadRcFile("lyxrc");
344
345         // Ensure that we have really read a bind file, so that LyX is
346         // usable.
347         if (!lyxrc->hasBindFile)
348                 lyxrc->ReadBindFile();
349
350         if (lyxerr.debugging(Error::LYXRC)) {
351                 lyxrc->Print();
352         }
353
354         // Create temp directory        
355         system_tempdir = CreateLyXTmpDir(lyxrc->tempdir_path);
356         if (lyxerr.debugging(Error::INIT)) {
357                 lyxerr.print("LyX tmp dir: `" + system_tempdir + '\'');
358         }
359
360         // load the lastfiles mini-database
361         lyxerr.debug("Reading lastfiles `" + lyxrc->lastfiles + "'...", 
362                       Error::INIT);
363         lastfiles = new LastFiles(lyxrc->lastfiles, 
364                                   lyxrc->check_lastfiles,
365                                   lyxrc->num_lastfiles);
366
367         // start up the lyxserver. (is this a bit early?) (Lgb)
368         // 0.12 this will be way to early, we need the GUI to be initialized
369         // first, so move it for now.
370         // lyxserver = new LyXServer;
371 }
372
373
374 // This one is not allowed to use anything on the main form, since that
375 // one does not exist yet. (Asger)
376 void LyX::queryUserLyXDir()
377 {
378         // Does user directory exist?
379         FileInfo fileInfo(user_lyxdir);
380         if (fileInfo.isOK() && fileInfo.isDir()) {
381                 first_start = false;
382                 return;
383         } else {
384                 first_start = true;
385         }
386         
387         // Nope
388         if (!AskQuestion(_("You don't have a personal LyX directory."),
389                          _("It is needed to keep your own configuration."),
390                          _("Should I try to set it up for you (recommended)?"))) {
391                 lyxerr.print(_("Running without personal LyX directory."));
392                 // No, let's use $HOME instead.
393                 user_lyxdir = getEnvPath("HOME");
394                 return;
395         }
396
397         // Tell the user what is going on
398         lyxerr.print(_("LyX: Creating directory ") + user_lyxdir + _(" and running configure..."));
399
400         // Create directory structure
401         if (!createDirectory(user_lyxdir, 0755)) {
402                 // Failed, let's use $HOME instead.
403                 user_lyxdir = getEnvPath("HOME");
404                 lyxerr.print(_("Failed. Will use ") + user_lyxdir + _(" instead."));
405                 return;
406         }
407
408         // Run configure in user lyx directory
409         PathPush(user_lyxdir);
410         system(AddName(system_lyxdir,"configure").c_str());
411         PathPop();
412         lyxerr.print(LString("LyX: ") + _("Done!"));
413 }
414
415
416 // Read the rc file `name'
417 void LyX::ReadRcFile(LString const & name)
418 {
419         lyxerr.debug("About to read "+name+"...", Error::INIT);
420         
421         LString lyxrc_path = LibFileSearch(LString(), name);
422         if (!lyxrc_path.empty()){
423                 lyxerr.debug("Found "+name+" in " + lyxrc_path, Error::INIT);
424                 if (lyxrc->Read(lyxrc_path) < 0) { 
425                         WriteAlert(_("LyX Warning!"), 
426                                    _("Error while reading ")+lyxrc_path+".",
427                                    _("Using built-in defaults."));
428                 }
429         } else
430                 lyxerr.debug("Could not find "+name, Error::INIT);
431 }
432
433
434 // Set debugging level and report result to user
435 void setDebuggingLevel(int dbgLevel)
436 {
437         lyxerr.print(LString(_("Setting debug level to ")) + dbgLevel);
438         lyxerr.setDebugLevel(dbgLevel);
439         lyxerr.debug(LString("Debugging INFO #") + int(Error::INFO),
440                      Error::INFO);
441         lyxerr.debug(LString("Debugging INIT #") + int(Error::INIT),
442                      Error::INIT);
443         lyxerr.debug(LString("Debugging KEY #") + int(Error::KEY),
444                      Error::KEY);
445         lyxerr.debug(LString("Debugging TOOLBAR #") + int(Error::TOOLBAR), 
446                      Error::TOOLBAR);
447         lyxerr.debug(LString("Debugging LEX and PARSER #") +
448                      int(Error::LEX_PARSER),
449                      Error::LEX_PARSER);
450         lyxerr.debug(LString("Debugging LYXRC #") + int(Error::LYXRC),
451                      Error::LYXRC);
452         lyxerr.debug(LString("Debugging KBMAP #") + int(Error::KBMAP),
453                      Error::KBMAP);
454         lyxerr.debug(LString("Debugging LATEX #") + int(Error::LATEX),
455                      Error::LATEX);
456         lyxerr.debug(LString("Debugging MATHED #") + int(Error::MATHED), 
457                      Error::MATHED);
458         lyxerr.debug(LString("Debugging FONT #") + int(Error::FONT),
459                      Error::FONT);
460         lyxerr.debug(LString("Debugging TCLASS #") + int(Error::TCLASS), 
461                      Error::TCLASS);
462         lyxerr.debug(LString("Debugging LYXVC #") + int(Error::LYXVC),
463                      Error::LYXVC);
464         lyxerr.debug(LString("Debugging LYXSERVER #") + int(Error::LYXSERVER),
465                      Error::LYXVC);
466 }
467
468
469 // Give command line help
470 void commandLineHelp()
471 {
472         lyxerr.print(_("LyX " LYX_VERSION " of " LYX_RELEASE ".\n"));
473         lyxerr.print(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"));
474         lyxerr.print(_("Command line switches (case sensitive):"));
475         lyxerr.print(_("   -help           summarize LyX usage"));
476         lyxerr.print(_("   -sysdir x       try to set system directory to x"));
477         lyxerr.print(_("   -width x        set the width of the main window"));
478         lyxerr.print(_("   -height y       set the height of the main window"));
479         lyxerr.print(_("   -xpos x         set the x position of the main window"));
480         lyxerr.print(_("   -ypos y         set the y position of the main window"));
481         lyxerr.print(_("   -dbg n          where n is a sum of debugging options. Try -dbg 65535 -help"));
482         lyxerr.print(_("   -Reverse        swaps foreground & background colors"));
483         lyxerr.print(_("   -Mono           runs LyX in black and white mode"));
484         lyxerr.print(_("   -FastSelection  use a fast routine for drawing selections\n"));
485         lyxerr.print(_("Check the LyX man page for more options."));
486 }
487
488
489 bool LyX::easyParse(int *argc, char *argv[])
490 {
491         bool gui = true;
492         for(int i=1; i < *argc; i++) {
493                 LString arg = argv[i];
494                 // Check for -dbg int
495                 if (arg == "-dbg") {
496                         if (i+1 < *argc) {
497                                 int erri = 0;
498                                 sscanf(argv[i+1],"%d", &erri);
499
500                                 setDebuggingLevel(erri);
501
502                                 // Now, remove these two arguments by shifting
503                                 // the following two places down.
504                                 (*argc) -= 2;
505                                 for (int j=i; j < (*argc); j++)
506                                         argv[j] = argv[j+2];
507                                 i--; // After shift, check this number again.
508                         } else
509                                 lyxerr.print(_("Missing number for -dbg switch!"));
510                 } 
511                 // Check for "-sysdir"
512                 else if (arg == "-sysdir") {
513                         if (i+1 < *argc) {
514                                 system_lyxdir = argv[i+1];
515
516                                 // Now, remove these two arguments by shifting
517                                 // the following two places down.
518                                 (*argc) -= 2;
519                                 for (int j=i; j < (*argc); j++)
520                                         argv[j] = argv[j+2];
521                                 i--; // After shift, check this number again.
522                         } else
523                                 lyxerr.print(_("Missing directory for -sysdir switch!"));
524                 // Check for --help or -help
525                 } else if (arg == "--help" || arg == "-help") {
526                         commandLineHelp();
527                         exit(0);
528                 } 
529                 // Check for "-nw": No window
530                 else if (arg == "-nw") {
531                         gui = false;
532                 }
533         }
534         return gui;
535 }
536
537
538 void error_handler(int err_sig)
539 {
540         switch (err_sig) {
541         case SIGHUP:
542                 fprintf(stderr, "\nlyx: SIGHUP signal caught\n");
543                 break;
544         case SIGINT:
545                 // no comments
546                 break;
547         case SIGFPE:
548                 fprintf(stderr, "\nlyx: SIGFPE signal caught\n");
549                 break;
550         case SIGSEGV:
551                 fprintf(stderr, "\nlyx: SIGSEGV signal caught\n");
552                 fprintf(stderr,
553                         "Sorry, you have found a bug in LyX."
554                         " If possible, please read 'Known bugs'\n"
555                         "under the Help menu and then send us "
556                         "a full bug report. Thanks!\n");
557                 break;
558         case SIGTERM:
559                 // no comments
560                 break;
561         }
562    
563         // Deinstall the signal handlers
564         signal(SIGHUP, SIG_DFL);
565         signal(SIGINT, SIG_DFL);
566         signal(SIGFPE, SIG_DFL);
567         signal(SIGSEGV, SIG_DFL);
568         signal(SIGTERM, SIG_DFL);
569
570         bufferlist.emergencyWriteAll();
571
572         lyxerr.print("Bye.");
573         if(err_sig!=SIGHUP && (getenv("LYXDEBUG") || err_sig == SIGSEGV))
574                 abort();
575         exit(0);
576 }