Remove useless indirection for {backspace,delete}key resources.
[dana/urxvt.git] / src / init.C
1 /*----------------------------------------------------------------------*
2  * File:        init.C
3  *----------------------------------------------------------------------*
4  *
5  * All portions of code are copyright by their respective author/s.
6  * Copyright (c) 1992      John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
7  *                              - original version
8  * Copyright (c) 1994      Robert Nation <nation@rocket.sanders.lockheed.com>
9  *                              - extensive modifications
10  * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
11  *                              - extensive modifications
12  * Copyright (c) 1999      D J Hawkey Jr <hawkeyd@visi.com>
13  *                              - QNX support
14  * Copyright (c) 2003-2006 Marc Lehmann <pcg@goof.com>
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29  *---------------------------------------------------------------------*/
30 /*
31  * Initialisation routines.
32  */
33
34 #include "../config.h"          /* NECESSARY */
35 #include "rxvt.h"               /* NECESSARY */
36 #include "rxvtutil.h"
37 #include "init.h"
38
39 #include <limits>
40
41 #include <csignal>
42
43 const char *const def_colorName[] =
44   {
45     COLOR_FOREGROUND,
46     COLOR_BACKGROUND,
47     /* low-intensity colors */
48     "rgb:00/00/00",             // 0: black             (Black)
49     "rgb:cd/00/00",             // 1: red               (Red3)
50     "rgb:00/cd/00",             // 2: green             (Green3)
51     "rgb:cd/cd/00",             // 3: yellow            (Yellow3)
52     "rgb:00/00/cd",             // 4: blue              (Blue3)
53     "rgb:cd/00/cd",             // 5: magenta           (Magenta3)
54     "rgb:00/cd/cd",             // 6: cyan              (Cyan3)
55 # ifdef XTERM_COLORS                                    
56     "rgb:e5/e5/e5",             // 7: white             (Grey90)
57 # else                                                  
58     "rgb:fa/eb/d7",             // 7: white             (AntiqueWhite)
59 # endif
60     /* high-intensity colors */
61 # ifdef XTERM_COLORS
62     "rgb:4d/4d/4d",             // 8: bright black      (Grey30)
63 # else
64     "rgb:40/40/40",             // 8: bright black      (Grey25)
65 # endif
66     "rgb:ff/00/00",             // 1/9: bright red      (Reed)
67     "rgb:00/ff/00",             // 2/10: bright green   (Green)
68     "rgb:ff/ff/00",             // 3/11: bright yellow  (Yellow)
69     "rgb:00/00/ff",             // 4/12: bright blue    (Blue)
70     "rgb:ff/00/ff",             // 5/13: bright magenta (Magenta)
71     "rgb:00/ff/ff",             // 6/14: bright cyan    (Cyan)
72     "rgb:ff/ff/ff",             // 7/15: bright white   (White)
73
74     // 88 xterm colours
75     "rgb:00/00/00",
76     "rgb:00/00/8b",
77     "rgb:00/00/cd",
78     "rgb:00/00/ff",
79     "rgb:00/8b/00",
80     "rgb:00/8b/8b",
81     "rgb:00/8b/cd",
82     "rgb:00/8b/ff",
83     "rgb:00/cd/00",
84     "rgb:00/cd/8b",
85     "rgb:00/cd/cd",
86     "rgb:00/cd/ff",
87     "rgb:00/ff/00",
88     "rgb:00/ff/8b",
89     "rgb:00/ff/cd",
90     "rgb:00/ff/ff",
91     "rgb:8b/00/00",
92     "rgb:8b/00/8b",
93     "rgb:8b/00/cd",
94     "rgb:8b/00/ff",
95     "rgb:8b/8b/00",
96     "rgb:8b/8b/8b",
97     "rgb:8b/8b/cd",
98     "rgb:8b/8b/ff",
99     "rgb:8b/cd/00",
100     "rgb:8b/cd/8b",
101     "rgb:8b/cd/cd",
102     "rgb:8b/cd/ff",
103     "rgb:8b/ff/00",
104     "rgb:8b/ff/8b",
105     "rgb:8b/ff/cd",
106     "rgb:8b/ff/ff",
107     "rgb:cd/00/00",
108     "rgb:cd/00/8b",
109     "rgb:cd/00/cd",
110     "rgb:cd/00/ff",
111     "rgb:cd/8b/00",
112     "rgb:cd/8b/8b",
113     "rgb:cd/8b/cd",
114     "rgb:cd/8b/ff",
115     "rgb:cd/cd/00",
116     "rgb:cd/cd/8b",
117     "rgb:cd/cd/cd",
118     "rgb:cd/cd/ff",
119     "rgb:cd/ff/00",
120     "rgb:cd/ff/8b",
121     "rgb:cd/ff/cd",
122     "rgb:cd/ff/ff",
123     "rgb:ff/00/00",
124     "rgb:ff/00/8b",
125     "rgb:ff/00/cd",
126     "rgb:ff/00/ff",
127     "rgb:ff/8b/00",
128     "rgb:ff/8b/8b",
129     "rgb:ff/8b/cd",
130     "rgb:ff/8b/ff",
131     "rgb:ff/cd/00",
132     "rgb:ff/cd/8b",
133     "rgb:ff/cd/cd",
134     "rgb:ff/cd/ff",
135     "rgb:ff/ff/00",
136     "rgb:ff/ff/8b",
137     "rgb:ff/ff/cd",
138     "rgb:ff/ff/ff",
139     "rgb:2e/2e/2e",
140     "rgb:5c/5c/5c",
141     "rgb:73/73/73",
142     "rgb:8b/8b/8b",
143     "rgb:a2/a2/a2",
144     "rgb:b9/b9/b9",
145     "rgb:d0/d0/d0",
146     "rgb:e7/e7/e7",
147
148 #ifndef NO_CURSORCOLOR
149     COLOR_CURSOR_BACKGROUND,
150     COLOR_CURSOR_FOREGROUND,
151 #endif                          /* ! NO_CURSORCOLOR */
152     NULL,                       /* Color_pointer_fg               */
153     NULL,                       /* Color_pointer_bg               */
154     NULL,                       /* Color_border                   */
155 #ifndef NO_BOLD_UNDERLINE_REVERSE
156     NULL,                       /* Color_BD                       */
157     NULL,                       /* Color_IT                       */
158     NULL,                       /* Color_UL                       */
159     NULL,                       /* Color_RV                       */
160 #endif                          /* ! NO_BOLD_UNDERLINE_REVERSE */
161 #if ENABLE_FRILLS
162     NULL,                       // Color_underline
163 #endif
164 #ifdef OPTION_HC
165     NULL,
166 #endif
167 #ifdef KEEP_SCROLLCOLOR
168     COLOR_SCROLLBAR,
169     COLOR_SCROLLTROUGH,
170 #endif                          /* KEEP_SCROLLCOLOR */
171 #if ENABLE_TRANSPARENCY
172     NULL,
173 #endif
174 #if OFF_FOCUS_FADING
175     "rgb:00/00/00",
176 #endif
177   };
178
179 bool
180 rxvt_term::init_vars ()
181 {
182   pix_colors           = //
183   pix_colors_focused   = new rxvt_color [TOTAL_COLORS];
184 #ifdef OFF_FOCUS_FADING
185   pix_colors_unfocused = new rxvt_color [TOTAL_COLORS];
186 #endif
187
188
189   MEvent.time = CurrentTime;
190   MEvent.button = AnyButton;
191   want_refresh = 1;
192   priv_modes = SavedModes = PrivMode_Default;
193   ncol = 80;
194   nrow = 24;
195   int_bwidth = INTERNALBORDERWIDTH;
196   ext_bwidth = EXTERNALBORDERWIDTH;
197   lineSpace = LINESPACE;
198   saveLines = SAVELINES;
199   numpix_colors = TOTAL_COLORS;
200
201   refresh_type = SLOW_REFRESH;
202
203   oldcursor.row = oldcursor.col = -1;
204 #ifdef HAVE_BG_PIXMAP
205 #ifdef HAVE_AFTERIMAGE
206   bgPixmap.original_asim = NULL;
207 #endif
208   /*  bgPixmap.w = bgPixmap.h = 0; */
209 #ifdef XPM_BACKGROUND
210   bgPixmap.h_scale = bgPixmap.v_scale = 0;
211   bgPixmap.h_align = bgPixmap.v_align = 0;
212 #endif
213   bgPixmap.flags = 0;
214   bgPixmap.pixmap = None;
215 #endif
216   last_bot = last_state = -1;
217
218   set_option (Opt_scrollBar);
219   set_option (Opt_scrollTtyOutput);
220   set_option (Opt_jumpScroll);
221   set_option (Opt_skipScroll);
222   set_option (Opt_secondaryScreen);
223   set_option (Opt_secondaryScroll);
224   set_option (Opt_pastableTabs);
225   set_option (Opt_intensityStyles);
226   set_option (Opt_iso14755_52);
227
228   return true;
229 }
230
231 void
232 rxvt_term::init_secondary ()
233 {
234   int i;
235
236   /*
237    * Close all unused file descriptors
238    * We don't want them, we don't need them.
239    */
240   if ((i = open ("/dev/null", O_RDONLY)) < 0)
241     {
242       /* TODO: BOO HISS */
243       dup2 (STDERR_FILENO, STDIN_FILENO);
244     }
245   else if (i > STDIN_FILENO)
246     {
247       dup2 (i, STDIN_FILENO);
248       close (i);
249     }
250
251   dup2 (STDERR_FILENO, STDOUT_FILENO);
252
253 #if 0 // schmorp sayz closing filies is murder
254   for (i = STDERR_FILENO + 1; i < num_fds; i++)
255     {
256 #ifdef __sgi                    /* Alex Coventry says we need 4 & 7 too */
257       if (i == 4 || i == 7)
258         continue;
259 #endif
260       close (i);
261     }
262 #endif
263 }
264
265 /*----------------------------------------------------------------------*/
266 const char **
267 rxvt_term::init_resources (int argc, const char *const *argv)
268 {
269   int i, r_argc;
270   const char **cmd_argv, **r_argv;
271
272   /*
273    * Look for -e option. Find => split and make cmd_argv[] of command args
274    */
275   for (r_argc = 0; r_argc < argc; r_argc++)
276     if (!strcmp (argv[r_argc], "-e"))
277       break;
278
279   r_argv = (const char **)rxvt_malloc (sizeof (char *) * (r_argc + 1));
280
281   for (i = 0; i < r_argc; i++)
282     r_argv[i] = (const char *)argv[i];
283
284   r_argv[i] = NULL;
285
286   if (r_argc == argc)
287     cmd_argv = NULL;
288   else
289     {
290       cmd_argv = (const char **)rxvt_malloc (sizeof (char *) * (argc - r_argc));
291
292       for (i = 0; i < argc - r_argc - 1; i++)
293         cmd_argv[i] = (const char *)argv[i + r_argc + 1];
294
295       cmd_argv[i] = NULL;
296     }
297
298   rs[Rs_name] = rxvt_basename (argv[0]);
299
300   /*
301    * Open display, get options/resources and create the window
302    */
303
304   if ((rs[Rs_display_name] = getenv ("DISPLAY")) == NULL)
305     rs[Rs_display_name] = ":0";
306
307   get_options (r_argc, r_argv);
308
309   if (!(display = displays.get (rs[Rs_display_name])))
310     rxvt_fatal ("can't open display %s, aborting.\n", rs[Rs_display_name]);
311
312   // using a local pointer decreases code size a lot
313   xa = display->xa;
314
315   set (display);
316   extract_resources ();
317
318 #if XFT
319   if (rs[Rs_depth])
320     select_visual (strtol (rs[Rs_depth], 0, 0));
321 #endif
322
323 #ifdef HAVE_AFTERIMAGE
324   asv = create_asvisual_for_id (dpy, display->screen, depth, XVisualIDFromVisual (visual), cmap, NULL);
325 #endif
326   free (r_argv);
327
328   for (int i = NUM_RESOURCES; i--; )
329     if (rs [i] == resval_undef)
330       rs [i] = 0;
331
332 #if ENABLE_PERL
333   if (!rs[Rs_perl_ext_1])
334     rs[Rs_perl_ext_1] = "default";
335
336   if ((rs[Rs_perl_ext_1] && *rs[Rs_perl_ext_1])
337       || (rs[Rs_perl_ext_2] && *rs[Rs_perl_ext_2])
338       || (rs[Rs_perl_eval] && *rs[Rs_perl_eval]))
339     {
340       rxvt_perl.init (this);
341       HOOK_INVOKE ((this, HOOK_INIT, DT_END));
342     }
343 #endif
344
345   /*
346    * set any defaults not already set
347    */
348   if (cmd_argv && cmd_argv[0])
349     {
350       if (!rs[Rs_title])
351         rs[Rs_title] = rxvt_basename (cmd_argv[0]);
352       if (!rs[Rs_iconName])
353         rs[Rs_iconName] = rs[Rs_title];
354     }
355   else
356     {
357       if (!rs[Rs_title])
358         rs[Rs_title] = rs[Rs_name];
359       if (!rs[Rs_iconName])
360         rs[Rs_iconName] = rs[Rs_name];
361     }
362
363   if (rs[Rs_saveLines] && (i = atoi (rs[Rs_saveLines])) >= 0)
364     saveLines = min (i, MAX_SAVELINES);
365
366 #if ENABLE_FRILLS
367   if (rs[Rs_int_bwidth] && (i = atoi (rs[Rs_int_bwidth])) >= 0)
368     int_bwidth = min (i, std::numeric_limits<int16_t>::max ());
369
370   if (rs[Rs_ext_bwidth] && (i = atoi (rs[Rs_ext_bwidth])) >= 0)
371     ext_bwidth = min (i, std::numeric_limits<int16_t>::max ());
372
373   if (rs[Rs_lineSpace] && (i = atoi (rs[Rs_lineSpace])) >= 0)
374     lineSpace = min (i, std::numeric_limits<int16_t>::max ());
375 #endif
376
377 #ifdef POINTER_BLANK
378   if (rs[Rs_pointerBlankDelay] && (i = atoi (rs[Rs_pointerBlankDelay])) >= 0)
379     pointerBlankDelay = i;
380   else
381     pointerBlankDelay = 2;
382 #endif
383
384   /* no point having a scrollbar without having any scrollback! */
385   if (!saveLines)
386     set_option (Opt_scrollBar, 0);
387
388 #ifdef PRINTPIPE
389   if (!rs[Rs_print_pipe])
390     rs[Rs_print_pipe] = PRINTPIPE;
391 #endif
392
393   if (!rs[Rs_cutchars])
394     rs[Rs_cutchars] = CUTCHARS;
395
396 #ifndef NO_BACKSPACE_KEY
397   if (!rs[Rs_backspace_key])
398 # ifdef DEFAULT_BACKSPACE
399     rs[Rs_backspace_key] = DEFAULT_BACKSPACE;
400 # else
401     rs[Rs_backspace_key] = "DEC";       /* can toggle between \010 or \177 */
402 # endif
403 #endif
404
405 #ifndef NO_DELETE_KEY
406   if (!rs[Rs_delete_key])
407 # ifdef DEFAULT_DELETE
408     rs[Rs_delete_key] = DEFAULT_DELETE;
409 # else
410     rs[Rs_delete_key] = "\033[3~";
411 # endif
412 #endif
413
414 #ifdef HAVE_SCROLLBARS
415   setup_scrollbar (rs[Rs_scrollBar_align], rs[Rs_scrollstyle], rs[Rs_scrollBar_thickness]);
416 #endif
417
418 #ifdef XTERM_REVERSE_VIDEO
419   /* this is how xterm implements reverseVideo */
420   if (option (Opt_reverseVideo))
421     {
422       if (!rs[Rs_color + Color_fg])
423         rs[Rs_color + Color_fg] = def_colorName[Color_bg];
424
425       if (!rs[Rs_color + Color_bg])
426         rs[Rs_color + Color_bg] = def_colorName[Color_fg];
427     }
428 #endif
429
430   for (i = 0; i < NRS_COLORS; i++)
431     if (!rs[Rs_color + i])
432       rs[Rs_color + i] = def_colorName[i];
433
434 #ifndef XTERM_REVERSE_VIDEO
435   /* this is how we implement reverseVideo */
436   if (option (Opt_reverseVideo))
437     ::swap (rs[Rs_color + Color_fg], rs[Rs_color + Color_bg]);
438 #endif
439
440   /* convenient aliases for setting fg/bg to colors */
441   color_aliases (Color_fg);
442   color_aliases (Color_bg);
443 #ifndef NO_CURSORCOLOR
444   color_aliases (Color_cursor);
445   color_aliases (Color_cursor2);
446 #endif                          /* NO_CURSORCOLOR */
447   color_aliases (Color_pointer_fg);
448   color_aliases (Color_pointer_bg);
449   color_aliases (Color_border);
450 #ifndef NO_BOLD_UNDERLINE_REVERSE
451   color_aliases (Color_BD);
452   color_aliases (Color_UL);
453   color_aliases (Color_RV);
454 #endif                          /* ! NO_BOLD_UNDERLINE_REVERSE */
455
456   if (!rs[Rs_color + Color_border])
457     rs[Rs_color + Color_border] = rs[Rs_color + Color_bg];
458
459   return cmd_argv;
460 }
461
462 /*----------------------------------------------------------------------*/
463 void
464 rxvt_term::init_env ()
465 {
466   int i;
467   char *val;
468
469 #ifdef DISPLAY_IS_IP
470   /* Fixup display_name for export over pty to any interested terminal
471    * clients via "ESC[7n" (e.g. shells).  Note we use the pure IP number
472    * (for the first non-loopback interface) that we get from
473    * rxvt_network_display ().  This is more "name-resolution-portable", if you
474    * will, and probably allows for faster x-client startup if your name
475    * server is beyond a slow link or overloaded at client startup.  Of
476    * course that only helps the shell's child processes, not us.
477    *
478    * Giving out the display_name also affords a potential security hole
479    */
480   val = rxvt_network_display (rs[Rs_display_name]);
481   rs[Rs_display_name] = (const char *)val;
482
483   if (val == NULL)
484 #endif                          /* DISPLAY_IS_IP */
485     val = XDisplayString (dpy);
486
487   if (rs[Rs_display_name] == NULL)
488     rs[Rs_display_name] = val;   /* use broken `:0' value */
489
490   i = strlen (val);
491   env_display = (char *)rxvt_malloc (i + 9);
492
493   sprintf (env_display, "DISPLAY=%s", val);
494
495   sprintf (env_windowid, "WINDOWID=%lu", (unsigned long)parent[0]);
496
497   /* add entries to the environment:
498    * @ DISPLAY:   in case we started with -display
499    * @ WINDOWID:  X window id number of the window
500    * @ COLORTERM: terminal sub-name and also indicates its color
501    * @ TERM:      terminal name
502    * @ TERMINFO:  path to terminfo directory
503    * @ COLORFGBG: fg;bg color codes
504    */
505   putenv (env_display);
506   putenv (env_windowid);
507
508   if (env_colorfgbg)
509     putenv (env_colorfgbg);
510
511 #ifdef RXVT_TERMINFO
512   putenv ("TERMINFO=" RXVT_TERMINFO);
513 #endif
514
515   if (depth <= 2)
516     putenv ("COLORTERM=" COLORTERMENV "-mono");
517   else
518     putenv ("COLORTERM=" COLORTERMENVFULL);
519
520   if (rs[Rs_term_name] != NULL)
521     {
522       env_term = (char *)rxvt_malloc (strlen (rs[Rs_term_name]) + 6);
523       sprintf (env_term, "TERM=%s", rs[Rs_term_name]);
524       putenv (env_term);
525     }
526   else
527     putenv ("TERM=" TERMENV);
528
529 #ifdef HAVE_UNSETENV
530   /* avoid passing old settings and confusing term size */
531   unsetenv ("LINES");
532   unsetenv ("COLUMNS");
533   unsetenv ("TERMCAP");        /* terminfo should be okay */
534 #endif                          /* HAVE_UNSETENV */
535 }
536
537 /*----------------------------------------------------------------------*/
538 /*
539  * This is more or less stolen straight from XFree86 xterm.
540  * This should support all European type languages.
541  */
542 void
543 rxvt_term::set_locale (const char *locale)
544 {
545   set_environ (envv);
546
547 #if HAVE_XSETLOCALE || HAVE_SETLOCALE
548   free (this->locale);
549   this->locale = setlocale (LC_CTYPE, locale);
550
551   if (!this->locale)
552     {
553       if (*locale)
554         {
555           rxvt_warn ("unable to set locale \"%s\", using C locale instead.\n", locale);
556           setlocale (LC_CTYPE, "C");
557         }
558       else
559         rxvt_warn ("default locale unavailable, check LC_* and LANG variables. Continuing.\n");
560
561       this->locale = "C";
562     }
563
564
565   this->locale = rxvt_strdup (this->locale);
566   SET_LOCALE (this->locale);
567   mbstate.reset ();
568 #endif
569
570 #if HAVE_NL_LANGINFO
571   char *codeset = strdup (nl_langinfo (CODESET));
572   // /^UTF.?8/i
573   enc_utf8 = (codeset[0] == 'U' || codeset[0] == 'u')
574           && (codeset[1] == 'T' || codeset[1] == 't')
575           && (codeset[2] == 'F' || codeset[2] == 'f')
576           && (codeset[3] == '8' || codeset[4] == '8');
577   free (codeset);
578 #else
579   enc_utf8 = 0;
580 #endif
581 }
582
583 void
584 rxvt_term::init_xlocale ()
585 {
586   set_environ (envv);
587
588 #ifdef USE_XIM
589   if (!locale)
590     rxvt_warn ("setting locale failed, working without locale support.\n");
591   else
592     {
593       set_string_property (xa[XA_WM_LOCALE_NAME], locale);
594
595       if (!XSupportsLocale ())
596         {
597           rxvt_warn ("the locale is not supported by Xlib, working without locale support.\n");
598           return;
599         }
600
601       im_ev.start (display);
602
603       /* see if we can connect already */
604       im_cb ();
605     }
606 #endif
607 }
608
609 /*----------------------------------------------------------------------*/
610 void
611 rxvt_term::init_command (const char *const *argv)
612 {
613   /*
614    * Initialize the command connection.
615    * This should be called after the X server connection is established.
616    */
617
618 #ifdef META8_OPTION
619   meta_char = option (Opt_meta8) ? 0x80 : C0_ESC;
620 #endif
621
622   get_ourmods ();
623
624   if (!option (Opt_scrollTtyOutput))
625     priv_modes |= PrivMode_TtyOutputInh;
626   if (option (Opt_scrollTtyKeypress))
627     priv_modes |= PrivMode_Keypress;
628   if (!option (Opt_jumpScroll))
629     priv_modes |= PrivMode_smoothScroll;
630
631 #ifndef NO_BACKSPACE_KEY
632   if (strcmp (rs[Rs_backspace_key], "DEC") == 0)
633     priv_modes |= PrivMode_HaveBackSpace;
634 #endif
635
636   /* add value for scrollBar */
637   if (scrollBar.state)
638     {
639       priv_modes |= PrivMode_scrollBar;
640       SavedModes |= PrivMode_scrollBar;
641     }
642
643   run_command (argv);
644 }
645
646 /*----------------------------------------------------------------------*/
647 void
648 rxvt_term::Get_Colours ()
649 {
650   int i;
651
652 #ifdef OFF_FOCUS_FADING
653   pix_colors = pix_colors_focused;
654 #endif
655   
656   for (i = 0; i < (depth <= 2 ? 2 : NRS_COLORS); i++)
657     {
658       const char *name = rs[Rs_color + i];
659
660       if (!name)
661         continue;
662
663       rxvt_color xcol;
664
665       if (!set_color (xcol, name))
666         {
667 #ifndef XTERM_REVERSE_VIDEO
668           if (i < 2 && option (Opt_reverseVideo))
669             name = def_colorName [1 - i];
670           else
671 #endif
672             name = def_colorName [i];
673
674           if (!name)
675             continue;
676
677           if (!set_color (xcol, name))
678             {
679               switch (i)
680                 {
681                   case Color_fg:
682                   case Color_bg:
683                     rxvt_warn ("unable to get foreground/background colour, continuing.\n");
684                     name = "";
685                     break;
686 #ifndef NO_CURSORCOLOR
687                   case Color_cursor2:
688 #endif
689                   case Color_pointer_fg:
690                     name = rs[Rs_color + Color_fg];
691                     xcol.set (this, name);
692                     break;
693                   default:
694                     name = rs[Rs_color + Color_bg];
695                     xcol.set (this, name);
696                     break;
697                 }
698             }
699         }
700
701       pix_colors[i] = xcol;
702       rs[Rs_color + i] = name;
703     }
704
705   if (depth <= 2)
706     {
707       if (!rs[Rs_color + Color_pointer_fg]) alias_color (Color_pointer_fg, Color_fg);
708       if (!rs[Rs_color + Color_pointer_bg]) alias_color (Color_pointer_bg, Color_bg);
709       if (!rs[Rs_color + Color_border]    ) alias_color (Color_border,     Color_fg);
710     }
711
712   /*
713    * get scrollBar shadow colors
714    *
715    * The calculations of topShadow/bottomShadow values are adapted
716    * from the fvwm window manager.
717    */
718 #ifdef KEEP_SCROLLCOLOR
719   if (depth <= 2)
720     {
721       /* Monochrome */
722       alias_color (Color_scroll,       Color_fg);
723       alias_color (Color_topShadow,    Color_bg);
724       alias_color (Color_bottomShadow, Color_bg);
725     }
726   else
727     {
728       pix_colors [Color_scroll].fade (this, 50, pix_colors [Color_bottomShadow]);
729
730       rgba cscroll;
731       pix_colors [Color_scroll].get (cscroll);
732
733       /* topShadowColor */
734       if (!pix_colors[Color_topShadow].set (this,
735                        rgba (
736                          min ((int)rgba::MAX_CC, max (cscroll.r / 5, cscroll.r) * 7 / 5),
737                          min ((int)rgba::MAX_CC, max (cscroll.g / 5, cscroll.g) * 7 / 5),
738                          min ((int)rgba::MAX_CC, max (cscroll.b / 5, cscroll.b) * 7 / 5),
739                          cscroll.a)
740                        ))
741         alias_color (Color_topShadow, Color_White);
742     }
743 #endif                          /* KEEP_SCROLLCOLOR */
744
745 #ifdef OFF_FOCUS_FADING
746   for (i = 0; i < (depth <= 2 ? 2 : NRS_COLORS); i++)
747     update_fade_color (i);
748 #endif
749 }
750
751 /*----------------------------------------------------------------------*/
752 /* color aliases, fg/bg bright-bold */
753 void
754 rxvt_term::color_aliases (int idx)
755 {
756   if (rs[Rs_color + idx] && isdigit (* (rs[Rs_color + idx])))
757     {
758       int i = atoi (rs[Rs_color + idx]);
759
760       if (i >= 8 && i <= 15)
761         {        /* bright colors */
762           i -= 8;
763           rs[Rs_color + idx] = rs[Rs_color + minBrightCOLOR + i];
764           return;
765         }
766
767       if (i >= 0 && i <= 7)   /* normal colors */
768         rs[Rs_color + idx] = rs[Rs_color + minCOLOR + i];
769     }
770 }
771
772 /*----------------------------------------------------------------------*/
773 /*
774  * Probe the modifier keymap to get the Meta (Alt) and Num_Lock settings
775  * Use resource ``modifier'' to override the Meta modifier
776  */
777 void
778 rxvt_term::get_ourmods ()
779 {
780   int i, j, k;
781   int requestedmeta, realmeta, realalt;
782   const char *cm, *rsmod;
783   XModifierKeymap *map;
784   KeyCode *kc;
785   const unsigned int modmasks[] =
786     {
787       Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
788     };
789
790   requestedmeta = realmeta = realalt = 0;
791   rsmod = rs[Rs_modifier];
792
793   if (rsmod
794       && strcasecmp (rsmod, "mod1") >= 0 && strcasecmp (rsmod, "mod5") <= 0)
795     requestedmeta = rsmod[3] - '0';
796
797   map = XGetModifierMapping (dpy);
798   kc = map->modifiermap;
799
800   for (i = 1; i < 6; i++)
801     {
802       k = (i + 2) * map->max_keypermod;       /* skip shift/lock/control */
803
804       for (j = map->max_keypermod; j--; k++)
805         {
806           if (kc[k] == 0)
807             break;
808
809           switch (XKeycodeToKeysym (dpy, kc[k], 0))
810             {
811               case XK_Num_Lock:
812                 ModNumLockMask = modmasks[i - 1];
813                 continue;
814
815               case XK_ISO_Level3_Shift:
816                 ModLevel3Mask = modmasks[i - 1];
817                 continue;
818
819               case XK_Meta_L:
820               case XK_Meta_R:
821                 cm = "meta";
822                 realmeta = i;
823                 break;
824
825               case XK_Alt_L:
826               case XK_Alt_R:
827                 cm = "alt";
828                 realalt = i;
829                 break;
830
831               case XK_Super_L:
832               case XK_Super_R:
833                 cm = "super";
834                 break;
835
836               case XK_Hyper_L:
837               case XK_Hyper_R:
838                 cm = "hyper";
839                 break;
840
841               default:
842                 continue;
843             }
844
845           if (rsmod && strncasecmp (rsmod, cm, strlen (cm)) == 0)
846             requestedmeta = i;
847         }
848     }
849
850   XFreeModifiermap (map);
851
852   i = requestedmeta ? requestedmeta
853     : realmeta      ? realmeta
854     : realalt       ? realalt
855     : 0;
856
857   if (i)
858     ModMetaMask = modmasks[i - 1];
859 }
860
861 /*----------------------------------------------------------------------*/
862 /* rxvt_Create_Windows () - Open and map the window */
863 void
864 rxvt_term::create_windows (int argc, const char *const *argv)
865 {
866   XClassHint classHint;
867   XWMHints wmHint;
868 #if ENABLE_FRILLS
869   MWMHints mwmhints = { };
870 #endif
871   XGCValues gcvalue;
872   XSetWindowAttributes attributes;
873   Window top, parent;
874
875   dLocal (Display *, dpy);
876
877   /* grab colors before netscape does */
878   Get_Colours ();
879
880   if (!set_fonts ())
881     rxvt_fatal ("unable to load base fontset, please specify a valid one using -fn, aborting.\n");
882
883   parent = display->root;
884
885   attributes.override_redirect = !!option (Opt_override_redirect);
886
887 #if ENABLE_FRILLS
888   if (option (Opt_borderLess))
889     {
890       if (XInternAtom (dpy, "_MOTIF_WM_INFO", True) == None)
891         {
892           // rxvt_warn("Window Manager does not support MWM hints.  Bypassing window manager control for borderless window.\n");
893           attributes.override_redirect = true;
894         }
895       else
896         {
897           mwmhints.flags = MWM_HINTS_DECORATIONS;
898         }
899     }
900 #endif
901
902 #if ENABLE_XEMBED
903   if (rs[Rs_embed])
904     {
905       XWindowAttributes wattr;
906
907       parent = strtol (rs[Rs_embed], 0, 0);
908
909       if (!XGetWindowAttributes (dpy, parent, &wattr))
910         rxvt_fatal ("invalid window-id specified with -embed, aborting.\n");
911
912       window_calc (wattr.width, wattr.height);
913     }
914 #endif
915
916   window_calc (0, 0);
917
918   /* sub-window placement & size in rxvt_resize_subwindows () */
919   attributes.background_pixel = pix_colors_focused [Color_border];
920   attributes.border_pixel     = pix_colors_focused [Color_border];
921   attributes.colormap         = cmap;
922
923   top = XCreateWindow (dpy, parent,
924                        szHint.x, szHint.y,
925                        szHint.width, szHint.height,
926                        ext_bwidth,
927                        depth, InputOutput, visual,
928                        CWColormap | CWBackPixel | CWBorderPixel | CWOverrideRedirect,
929                        &attributes);
930
931   this->parent[0] = top;
932
933   old_width = szHint.width;
934   old_height = szHint.height;
935
936   process_xterm_seq (XTerm_title,    rs[Rs_title],    CHAR_ST);
937   process_xterm_seq (XTerm_iconName, rs[Rs_iconName], CHAR_ST);
938
939   classHint.res_name  = (char *)rs[Rs_name];
940   classHint.res_class = (char *)RESCLASS;
941
942   wmHint.flags         = InputHint | StateHint | WindowGroupHint;
943   wmHint.input         = True;
944   wmHint.initial_state = option (Opt_iconic) ? IconicState : NormalState;
945   wmHint.window_group  = top;
946
947   XmbSetWMProperties (dpy, top, NULL, NULL, (char **)argv, argc,
948                       &szHint, &wmHint, &classHint);
949
950 #if ENABLE_FRILLS
951   if (mwmhints.flags)
952     XChangeProperty (dpy, top, xa[XA_MOTIF_WM_HINTS], xa[XA_MOTIF_WM_HINTS], 32,
953                      PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS);
954 #endif
955
956   Atom protocols[] = {
957     xa[XA_WM_DELETE_WINDOW],
958 #if ENABLE_EWMH
959     xa[XA_NET_WM_PING],
960 #endif
961   };
962
963   XSetWMProtocols (dpy, top, protocols, sizeof (protocols) / sizeof (protocols[0]));
964
965 #if ENABLE_FRILLS
966   if (rs[Rs_transient_for])
967     XSetTransientForHint (dpy, top, (Window)strtol (rs[Rs_transient_for], 0, 0));
968 #endif
969
970 #if ENABLE_EWMH
971   long pid = getpid ();
972
973   XChangeProperty (dpy, top,
974                    xa[XA_NET_WM_PID], XA_CARDINAL, 32,
975                    PropModeReplace, (unsigned char *)&pid, 1);
976
977   // _NET_WM_WINDOW_TYPE is NORMAL, which is the default
978 #endif
979
980   XSelectInput (dpy, top,
981                 KeyPressMask
982 #if (MOUSE_WHEEL && MOUSE_SLIP_WHEELING) || ENABLE_FRILLS || ISO_14755
983                 | KeyReleaseMask
984 #endif
985                 | FocusChangeMask | VisibilityChangeMask
986                 | ExposureMask | StructureNotifyMask);
987
988   termwin_ev.start (display, top);
989
990   /* vt cursor: Black-on-White is standard, but this is more popular */
991   TermWin_cursor = XCreateFontCursor (dpy, XC_xterm);
992
993 #ifdef HAVE_SCROLLBARS
994   /* cursor scrollBar: Black-on-White */
995   leftptr_cursor = XCreateFontCursor (dpy, XC_left_ptr);
996 #endif
997
998   /* the vt window */
999   vt = XCreateSimpleWindow (dpy, top,
1000                             window_vt_x, window_vt_y,
1001                             width, height,
1002                             0,
1003                             pix_colors_focused[Color_fg],
1004                             pix_colors_focused[Color_bg]);
1005
1006   attributes.bit_gravity = NorthWestGravity;
1007   XChangeWindowAttributes (dpy, vt, CWBitGravity, &attributes);
1008
1009   vt_emask = ExposureMask | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask;
1010
1011   if (option (Opt_pointerBlank))
1012     vt_emask |= PointerMotionMask;
1013   else
1014     vt_emask |= Button1MotionMask | Button3MotionMask;
1015
1016   vt_select_input ();
1017
1018   vt_ev.start (display, vt);
1019
1020   /* graphics context for the vt window */
1021   gcvalue.foreground         = pix_colors[Color_fg];
1022   gcvalue.background         = pix_colors[Color_bg];
1023   gcvalue.graphics_exposures = 0;
1024
1025   gc = XCreateGC (dpy, vt,
1026                   GCForeground | GCBackground | GCGraphicsExposures,
1027                   &gcvalue);
1028
1029   drawable = new rxvt_drawable (this, vt);
1030
1031 #ifdef RXVT_SCROLLBAR
1032   gcvalue.foreground = pix_colors[Color_topShadow];
1033   topShadowGC = XCreateGC (dpy, vt, GCForeground, &gcvalue);
1034   gcvalue.foreground = pix_colors[Color_bottomShadow];
1035   botShadowGC = XCreateGC (dpy, vt, GCForeground, &gcvalue);
1036   gcvalue.foreground = pix_colors[ (depth <= 2 ? Color_fg : Color_scroll)];
1037   scrollbarGC = XCreateGC (dpy, vt, GCForeground, &gcvalue);
1038 #endif
1039
1040 #ifdef OFF_FOCUS_FADING
1041   // initially we are in unfocused state
1042   if (rs[Rs_fade])
1043     pix_colors = pix_colors_unfocused;
1044 #endif
1045
1046   pointer_unblank ();
1047   scr_recolour ();
1048 }
1049
1050 /* ------------------------------------------------------------------------- *
1051  *                            GET TTY CURRENT STATE                          *
1052  * ------------------------------------------------------------------------- */
1053 void
1054 rxvt_get_ttymode (ttymode_t *tio, int erase)
1055 {
1056   /*
1057    * standard System V termios interface
1058    */
1059   if (GET_TERMIOS (STDIN_FILENO, tio) < 0)
1060     {
1061       // return error - use system defaults,
1062       // where possible, and zero elsewhere
1063       memset (tio, 0, sizeof (ttymode_t));
1064
1065       tio->c_cc[VINTR] = CINTR;
1066       tio->c_cc[VQUIT] = CQUIT;
1067       tio->c_cc[VERASE] = CERASE;
1068 #ifdef VERASE2
1069       tio->c_cc[VERASE2] = CERASE2;
1070 #endif
1071       tio->c_cc[VKILL] = CKILL;
1072       tio->c_cc[VSTART] = CSTART;
1073       tio->c_cc[VSTOP] = CSTOP;
1074       tio->c_cc[VSUSP] = CSUSP;
1075 # ifdef VDSUSP
1076       tio->c_cc[VDSUSP] = CDSUSP;
1077 # endif
1078 # ifdef VREPRINT
1079       tio->c_cc[VREPRINT] = CRPRNT;
1080 # endif
1081 # ifdef VDISCRD
1082       tio->c_cc[VDISCRD] = CFLUSH;
1083 # endif
1084 # ifdef VWERSE
1085       tio->c_cc[VWERSE] = CWERASE;
1086 # endif
1087 # ifdef VLNEXT
1088       tio->c_cc[VLNEXT] = CLNEXT;
1089 # endif
1090     }
1091
1092   tio->c_cc[VEOF] = CEOF;
1093   tio->c_cc[VEOL] = VDISABLE;
1094 # ifdef VEOL2
1095   tio->c_cc[VEOL2] = VDISABLE;
1096 # endif
1097 # ifdef VSWTC
1098   tio->c_cc[VSWTC] = VDISABLE;
1099 # endif
1100 # ifdef VSWTCH
1101   tio->c_cc[VSWTCH] = VDISABLE;
1102 # endif
1103 # if VMIN != VEOF
1104   tio->c_cc[VMIN] = 1;
1105 # endif
1106 # if VTIME != VEOL
1107   tio->c_cc[VTIME] = 0;
1108 # endif
1109
1110   if (erase != -1)
1111     tio->c_cc[VERASE] = (char)erase;
1112
1113   /* input modes */
1114   tio->c_iflag = (BRKINT | IGNPAR | ICRNL
1115 # ifdef IMAXBEL
1116                   | IMAXBEL
1117 # endif
1118                   | IXON);
1119
1120   /* output modes */
1121   tio->c_oflag = (OPOST | ONLCR);
1122
1123   /* control modes */
1124   tio->c_cflag = (CS8 | CREAD);
1125
1126   /* line discipline modes */
1127   tio->c_lflag = (ISIG | ICANON | IEXTEN | ECHO
1128 # if defined (ECHOCTL) && defined (ECHOKE)
1129                   | ECHOCTL | ECHOKE
1130 # endif
1131                   | ECHOE | ECHOK);
1132
1133   /*
1134    * Debugging
1135    */
1136 #ifdef DEBUG_TTYMODE
1137 #ifdef HAVE_TERMIOS_H
1138   /* c_iflag bits */
1139   fprintf (stderr, "Input flags\n");
1140
1141   /* cpp token stringize doesn't work on all machines <sigh> */
1142 # define FOO(flag,name)                 \
1143     if ((tio->c_iflag) & flag)          \
1144         fprintf (stderr, "%s ", name)
1145
1146   /* c_iflag bits */
1147   FOO (IGNBRK, "IGNBRK");
1148   FOO (BRKINT, "BRKINT");
1149   FOO (IGNPAR, "IGNPAR");
1150   FOO (PARMRK, "PARMRK");
1151   FOO (INPCK, "INPCK");
1152   FOO (ISTRIP, "ISTRIP");
1153   FOO (INLCR, "INLCR");
1154   FOO (IGNCR, "IGNCR");
1155   FOO (ICRNL, "ICRNL");
1156   FOO (IXON, "IXON");
1157   FOO (IXOFF, "IXOFF");
1158 # ifdef IUCLC
1159   FOO (IUCLC, "IUCLC");
1160 # endif
1161 # ifdef IXANY
1162   FOO (IXANY, "IXANY");
1163 # endif
1164 # ifdef IMAXBEL
1165   FOO (IMAXBEL, "IMAXBEL");
1166 # endif
1167
1168   fprintf (stderr, "\n");
1169
1170 # undef FOO
1171 # define FOO(entry, name)                                       \
1172     fprintf (stderr, "%-8s = %#04o\n", name, tio->c_cc [entry])
1173
1174   FOO (VINTR, "VINTR");
1175   FOO (VQUIT, "VQUIT");
1176   FOO (VERASE, "VERASE");
1177   FOO (VKILL, "VKILL");
1178   FOO (VEOF, "VEOF");
1179   FOO (VEOL, "VEOL");
1180 # ifdef VEOL2
1181   FOO (VEOL2, "VEOL2");
1182 # endif
1183 # ifdef VSWTC
1184   FOO (VSWTC, "VSWTC");
1185 # endif
1186 # ifdef VSWTCH
1187   FOO (VSWTCH, "VSWTCH");
1188 # endif
1189   FOO (VSTART, "VSTART");
1190   FOO (VSTOP, "VSTOP");
1191   FOO (VSUSP, "VSUSP");
1192 # ifdef VDSUSP
1193   FOO (VDSUSP, "VDSUSP");
1194 # endif
1195 # ifdef VREPRINT
1196   FOO (VREPRINT, "VREPRINT");
1197 # endif
1198 # ifdef VDISCRD
1199   FOO (VDISCRD, "VDISCRD");
1200 # endif
1201 # ifdef VWERSE
1202   FOO (VWERSE, "VWERSE");
1203 # endif
1204 # ifdef VLNEXT
1205   FOO (VLNEXT, "VLNEXT");
1206 # endif
1207
1208   fprintf (stderr, "\n");
1209 # undef FOO
1210 # endif                         /* HAVE_TERMIOS_H */
1211 #endif                          /* DEBUG_TTYMODE */
1212 }
1213
1214 /*----------------------------------------------------------------------*/
1215 /*
1216  * Run the command in a subprocess and return a file descriptor for the
1217  * master end of the pseudo-teletype pair with the command talking to
1218  * the slave.
1219  */
1220 void
1221 rxvt_term::run_command (const char *const *argv)
1222 {
1223 #if ENABLE_FRILLS
1224   if (rs[Rs_pty_fd])
1225     {
1226       pty->pty = atoi (rs[Rs_pty_fd]);
1227
1228       if (pty->pty >= 0)
1229         {
1230           if (getfd_hook)
1231             pty->pty = (*getfd_hook) (pty->pty);
1232
1233           if (pty->pty < 0 || fcntl (pty->pty, F_SETFL, O_NONBLOCK))
1234             rxvt_fatal ("unusable pty-fd filehandle, aborting.\n");
1235         }
1236     }
1237   else
1238 #endif
1239     if (!pty->get ())
1240       rxvt_fatal ("can't initialize pseudo-tty, aborting.\n");
1241
1242   int er;
1243
1244 #ifndef NO_BACKSPACE_KEY
1245   if (rs[Rs_backspace_key][0] && !rs[Rs_backspace_key][1])
1246     er = rs[Rs_backspace_key][0];
1247   else if (strcmp (rs[Rs_backspace_key], "DEC") == 0)
1248     er = '\177';            /* the initial state anyway */
1249   else
1250 #endif
1251     er = -1;
1252
1253   rxvt_get_ttymode (&tio, er);
1254   SET_TERMIOS (pty->tty, &tio);       /* init terminal attributes */
1255   pty->set_utf8_mode (enc_utf8);
1256
1257   /* set initial window size */
1258   tt_winch ();
1259
1260 #if ENABLE_FRILLS
1261   if (rs[Rs_pty_fd])
1262     return;
1263 #endif
1264
1265   /* spin off the command interpreter */
1266   switch (cmd_pid = fork ())
1267     {
1268       case -1:
1269         {
1270           cmd_pid = 0;
1271           rxvt_fatal ("can't fork, aborting.\n");
1272         }
1273       case 0:
1274         init_env ();
1275
1276         if (!pty->make_controlling_tty ())
1277           fprintf (stderr, "%s: could not obtain control of tty.", RESNAME);
1278         else
1279           {
1280             /* Reopen stdin, stdout and stderr over the tty file descriptor */
1281             dup2 (pty->tty, STDIN_FILENO);
1282             dup2 (pty->tty, STDOUT_FILENO);
1283             dup2 (pty->tty, STDERR_FILENO);
1284
1285             // close all our file handles that we do no longer need
1286             for (rxvt_term **t = termlist.begin (); t < termlist.end (); t++)
1287               {
1288                 if ((*t)->pty->pty > 2) close ((*t)->pty->pty);
1289                 if ((*t)->pty->tty > 2) close ((*t)->pty->tty);
1290               }
1291
1292             run_child (argv);
1293             fprintf (stderr, "%s: unable to exec child.", RESNAME);
1294           }
1295
1296         _exit (EXIT_FAILURE);
1297
1298       default:
1299         if (!option (Opt_utmpInhibit))
1300           pty->login (cmd_pid, option (Opt_loginShell), rs[Rs_display_name]);
1301
1302         pty->close_tty ();
1303
1304         child_ev.start (cmd_pid);
1305
1306         HOOK_INVOKE ((this, HOOK_CHILD_START, DT_INT, cmd_pid, DT_END));
1307         break;
1308     }
1309 }
1310
1311 /* ------------------------------------------------------------------------- *
1312  *                          CHILD PROCESS OPERATIONS                         *
1313  * ------------------------------------------------------------------------- */
1314 /*
1315  * The only open file descriptor is the slave tty - so no error messages.
1316  * returns are fatal
1317  */
1318 int
1319 rxvt_term::run_child (const char *const *argv)
1320 {
1321   char *login;
1322
1323   if (option (Opt_console))
1324     {     /* be virtual console, fail silently */
1325 #ifdef TIOCCONS
1326       unsigned int on = 1;
1327
1328       ioctl (STDIN_FILENO, TIOCCONS, &on);
1329 #elif defined (SRIOCSREDIR)
1330       int fd;
1331
1332       fd = open (CONSOLE, O_WRONLY, 0);
1333       if (fd >= 0)
1334         if (ioctl (fd, SRIOCSREDIR, NULL) < 0)
1335           close (fd);
1336 #endif                          /* SRIOCSREDIR */
1337     }
1338
1339   /* reset signals and spin off the command interpreter */
1340   signal (SIGINT,  SIG_DFL);
1341   signal (SIGQUIT, SIG_DFL);
1342   signal (SIGCHLD, SIG_DFL);
1343   signal (SIGHUP,  SIG_DFL);
1344   signal (SIGPIPE, SIG_DFL);
1345   /*
1346    * mimick login's behavior by disabling the job control signals
1347    * a shell that wants them can turn them back on
1348    */
1349 #ifdef SIGTSTP
1350   signal (SIGTSTP, SIG_IGN);
1351   signal (SIGTTIN, SIG_IGN);
1352   signal (SIGTTOU, SIG_IGN);
1353 #endif                          /* SIGTSTP */
1354
1355   // unblock signals (signals are blocked by iom.C
1356   sigset_t ss;
1357   sigemptyset (&ss);
1358   sigprocmask (SIG_SETMASK, &ss, 0);
1359
1360   /* command interpreter path */
1361   if (argv != NULL)
1362     {
1363 # ifdef DEBUG_CMD
1364       int             i;
1365
1366       for (i = 0; argv[i]; i++)
1367         fprintf (stderr, "argv [%d] = \"%s\"\n", i, argv[i]);
1368 # endif
1369
1370       execvp (argv[0], (char *const *)argv);
1371       /* no error message: STDERR is closed! */
1372     }
1373   else
1374     {
1375       const char *argv0, *shell;
1376
1377       if ((shell = getenv ("SHELL")) == NULL || *shell == '\0')
1378         shell = "/bin/sh";
1379
1380       argv0 = (const char *)rxvt_basename (shell);
1381
1382       if (option (Opt_loginShell))
1383         {
1384           login = (char *)rxvt_malloc (strlen (argv0) + 2);
1385
1386           login[0] = '-';
1387           strcpy (&login[1], argv0);
1388           argv0 = login;
1389         }
1390
1391       execlp (shell, argv0, NULL);
1392       /* no error message: STDERR is closed! */
1393     }
1394
1395   return -1;
1396 }
1397
1398 /*----------------------- end-of-file (C source) -----------------------*/