*** empty log message ***
[dana/urxvt.git] / src / init.C
1 /*--------------------------------*-C-*---------------------------------*
2  * File:        init.c
3  *----------------------------------------------------------------------*
4  * $Id: init.C,v 1.9 2003-12-02 21:49:46 pcg Exp $
5  *
6  * All portions of code are copyright by their respective author/s.
7  * Copyright (c) 1992      John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
8  *                              - original version
9  * Copyright (c) 1994      Robert Nation <nation@rocket.sanders.lockheed.com>
10  *                              - extensive modifications
11  * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
12  *                              - extensive modifications
13  * Copyright (c) 1999      D J Hawkey Jr <hawkeyd@visi.com>
14  *                              - QNX support
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 "init.h"
37
38 #include <signal.h>
39
40 const char *const def_colorName[] =
41   {
42     COLOR_FOREGROUND,
43     COLOR_BACKGROUND,
44     /* low-intensity colors */
45     "Black",                    /* 0: black             (#000000) */
46 #ifndef NO_BRIGHTCOLOR
47     "Red3",                     /* 1: red               (#CD0000) */
48     "Green3",                   /* 2: green             (#00CD00) */
49     "Yellow3",                  /* 3: yellow            (#CDCD00) */
50     "Blue3",                    /* 4: blue              (#0000CD) */
51     "Magenta3",                 /* 5: magenta           (#CD00CD) */
52     "Cyan3",                    /* 6: cyan              (#00CDCD) */
53 # ifdef XTERM_COLORS
54     "Grey90",                   /* 7: white             (#E5E5E5) */
55 # else
56     "AntiqueWhite",             /* 7: white             (#FAEBD7) */
57 # endif
58     /* high-intensity colors */
59 # ifdef XTERM_COLORS
60     "Grey30",                   /* 8: bright black      (#4D4D4D) */
61 # else
62     "Grey25",                   /* 8: bright black      (#404040) */
63 # endif
64 #endif                          /* NO_BRIGHTCOLOR */
65     "Red",                      /* 1/9: bright red      (#FF0000) */
66     "Green",                    /* 2/10: bright green   (#00FF00) */
67     "Yellow",                   /* 3/11: bright yellow  (#FFFF00) */
68     "Blue",                     /* 4/12: bright blue    (#0000FF) */
69     "Magenta",                  /* 5/13: bright magenta (#FF00FF) */
70     "Cyan",                     /* 6/14: bright cyan    (#00FFFF) */
71     "White",                    /* 7/15: bright white   (#FFFFFF) */
72 #ifdef TTY_256COLOR
73     "rgb:00/00/00",             /* default 16-255 color table     */
74     "rgb:00/00/2a",
75     "rgb:00/00/55",
76     "rgb:00/00/7f",
77     "rgb:00/00/aa",
78     "rgb:00/00/d4",
79     "rgb:00/2a/00",
80     "rgb:00/2a/2a",
81     "rgb:00/2a/55",
82     "rgb:00/2a/7f",
83     "rgb:00/2a/aa",
84     "rgb:00/2a/d4",
85     "rgb:00/55/00",
86     "rgb:00/55/2a",
87     "rgb:00/55/55",
88     "rgb:00/55/7f",
89     "rgb:00/55/aa",
90     "rgb:00/55/d4",
91     "rgb:00/7f/00",
92     "rgb:00/7f/2a",
93     "rgb:00/7f/55",
94     "rgb:00/7f/7f",
95     "rgb:00/7f/aa",
96     "rgb:00/7f/d4",
97     "rgb:00/aa/00",
98     "rgb:00/aa/2a",
99     "rgb:00/aa/55",
100     "rgb:00/aa/7f",
101     "rgb:00/aa/aa",
102     "rgb:00/aa/d4",
103     "rgb:00/d4/00",
104     "rgb:00/d4/2a",
105     "rgb:00/d4/55",
106     "rgb:00/d4/7f",
107     "rgb:00/d4/aa",
108     "rgb:00/d4/d4",
109     "rgb:2a/00/00",
110     "rgb:2a/00/2a",
111     "rgb:2a/00/55",
112     "rgb:2a/00/7f",
113     "rgb:2a/00/aa",
114     "rgb:2a/00/d4",
115     "rgb:2a/2a/00",
116     "rgb:2a/2a/2a",
117     "rgb:2a/2a/55",
118     "rgb:2a/2a/7f",
119     "rgb:2a/2a/aa",
120     "rgb:2a/2a/d4",
121     "rgb:2a/55/00",
122     "rgb:2a/55/2a",
123     "rgb:2a/55/55",
124     "rgb:2a/55/7f",
125     "rgb:2a/55/aa",
126     "rgb:2a/55/d4",
127     "rgb:2a/7f/00",
128     "rgb:2a/7f/2a",
129     "rgb:2a/7f/55",
130     "rgb:2a/7f/7f",
131     "rgb:2a/7f/aa",
132     "rgb:2a/7f/d4",
133     "rgb:2a/aa/00",
134     "rgb:2a/aa/2a",
135     "rgb:2a/aa/55",
136     "rgb:2a/aa/7f",
137     "rgb:2a/aa/aa",
138     "rgb:2a/aa/d4",
139     "rgb:2a/d4/00",
140     "rgb:2a/d4/2a",
141     "rgb:2a/d4/55",
142     "rgb:2a/d4/7f",
143     "rgb:2a/d4/aa",
144     "rgb:2a/d4/d4",
145     "rgb:55/00/00",
146     "rgb:55/00/2a",
147     "rgb:55/00/55",
148     "rgb:55/00/7f",
149     "rgb:55/00/aa",
150     "rgb:55/00/d4",
151     "rgb:55/2a/00",
152     "rgb:55/2a/2a",
153     "rgb:55/2a/55",
154     "rgb:55/2a/7f",
155     "rgb:55/2a/aa",
156     "rgb:55/2a/d4",
157     "rgb:55/55/00",
158     "rgb:55/55/2a",
159     "rgb:55/55/55",
160     "rgb:55/55/7f",
161     "rgb:55/55/aa",
162     "rgb:55/55/d4",
163     "rgb:55/7f/00",
164     "rgb:55/7f/2a",
165     "rgb:55/7f/55",
166     "rgb:55/7f/7f",
167     "rgb:55/7f/aa",
168     "rgb:55/7f/d4",
169     "rgb:55/aa/00",
170     "rgb:55/aa/2a",
171     "rgb:55/aa/55",
172     "rgb:55/aa/7f",
173     "rgb:55/aa/aa",
174     "rgb:55/aa/d4",
175     "rgb:55/d4/00",
176     "rgb:55/d4/2a",
177     "rgb:55/d4/55",
178     "rgb:55/d4/7f",
179     "rgb:55/d4/aa",
180     "rgb:55/d4/d4",
181     "rgb:7f/00/00",
182     "rgb:7f/00/2a",
183     "rgb:7f/00/55",
184     "rgb:7f/00/7f",
185     "rgb:7f/00/aa",
186     "rgb:7f/00/d4",
187     "rgb:7f/2a/00",
188     "rgb:7f/2a/2a",
189     "rgb:7f/2a/55",
190     "rgb:7f/2a/7f",
191     "rgb:7f/2a/aa",
192     "rgb:7f/2a/d4",
193     "rgb:7f/55/00",
194     "rgb:7f/55/2a",
195     "rgb:7f/55/55",
196     "rgb:7f/55/7f",
197     "rgb:7f/55/aa",
198     "rgb:7f/55/d4",
199     "rgb:7f/7f/00",
200     "rgb:7f/7f/2a",
201     "rgb:7f/7f/55",
202     "rgb:7f/7f/7f",
203     "rgb:7f/7f/aa",
204     "rgb:7f/7f/d4",
205     "rgb:7f/aa/00",
206     "rgb:7f/aa/2a",
207     "rgb:7f/aa/55",
208     "rgb:7f/aa/7f",
209     "rgb:7f/aa/aa",
210     "rgb:7f/aa/d4",
211     "rgb:7f/d4/00",
212     "rgb:7f/d4/2a",
213     "rgb:7f/d4/55",
214     "rgb:7f/d4/7f",
215     "rgb:7f/d4/aa",
216     "rgb:7f/d4/d4",
217     "rgb:aa/00/00",
218     "rgb:aa/00/2a",
219     "rgb:aa/00/55",
220     "rgb:aa/00/7f",
221     "rgb:aa/00/aa",
222     "rgb:aa/00/d4",
223     "rgb:aa/2a/00",
224     "rgb:aa/2a/2a",
225     "rgb:aa/2a/55",
226     "rgb:aa/2a/7f",
227     "rgb:aa/2a/aa",
228     "rgb:aa/2a/d4",
229     "rgb:aa/55/00",
230     "rgb:aa/55/2a",
231     "rgb:aa/55/55",
232     "rgb:aa/55/7f",
233     "rgb:aa/55/aa",
234     "rgb:aa/55/d4",
235     "rgb:aa/7f/00",
236     "rgb:aa/7f/2a",
237     "rgb:aa/7f/55",
238     "rgb:aa/7f/7f",
239     "rgb:aa/7f/aa",
240     "rgb:aa/7f/d4",
241     "rgb:aa/aa/00",
242     "rgb:aa/aa/2a",
243     "rgb:aa/aa/55",
244     "rgb:aa/aa/7f",
245     "rgb:aa/aa/aa",
246     "rgb:aa/aa/d4",
247     "rgb:aa/d4/00",
248     "rgb:aa/d4/2a",
249     "rgb:aa/d4/55",
250     "rgb:aa/d4/7f",
251     "rgb:aa/d4/aa",
252     "rgb:aa/d4/d4",
253     "rgb:d4/00/00",
254     "rgb:d4/00/2a",
255     "rgb:d4/00/55",
256     "rgb:d4/00/7f",
257     "rgb:d4/00/aa",
258     "rgb:d4/00/d4",
259     "rgb:d4/2a/00",
260     "rgb:d4/2a/2a",
261     "rgb:d4/2a/55",
262     "rgb:d4/2a/7f",
263     "rgb:d4/2a/aa",
264     "rgb:d4/2a/d4",
265     "rgb:d4/55/00",
266     "rgb:d4/55/2a",
267     "rgb:d4/55/55",
268     "rgb:d4/55/7f",
269     "rgb:d4/55/aa",
270     "rgb:d4/55/d4",
271     "rgb:d4/7f/00",
272     "rgb:d4/7f/2a",
273     "rgb:d4/7f/55",
274     "rgb:d4/7f/7f",
275     "rgb:d4/7f/aa",
276     "rgb:d4/7f/d4",
277     "rgb:d4/aa/00",
278     "rgb:d4/aa/2a",
279     "rgb:d4/aa/55",
280     "rgb:d4/aa/7f",
281     "rgb:d4/aa/aa",
282     "rgb:d4/aa/d4",
283     "rgb:d4/d4/00",
284     "rgb:d4/d4/2a",
285     "rgb:d4/d4/55",
286     "rgb:d4/d4/7f",
287     "rgb:d4/d4/aa",
288     "rgb:d4/d4/d4",
289     "rgb:08/08/08",
290     "rgb:12/12/12",
291     "rgb:1c/1c/1c",
292     "rgb:26/26/26",
293     "rgb:30/30/30",
294     "rgb:3a/3a/3a",
295     "rgb:44/44/44",
296     "rgb:4e/4e/4e",
297     "rgb:58/58/58",
298     "rgb:62/62/62",
299     "rgb:6c/6c/6c",
300     "rgb:76/76/76",
301     "rgb:80/80/80",
302     "rgb:8a/8a/8a",
303     "rgb:94/94/94",
304     "rgb:9e/9e/9e",
305     "rgb:a8/a8/a8",
306     "rgb:b2/b2/b2",
307     "rgb:bc/bc/bc",
308     "rgb:c6/c6/c6",
309     "rgb:d0/d0/d0",
310     "rgb:da/da/da",
311     "rgb:e4/e4/e4",
312     "rgb:ee/ee/ee",
313 #endif
314 #ifndef NO_CURSORCOLOR
315     COLOR_CURSOR_BACKGROUND,
316     COLOR_CURSOR_FOREGROUND,
317 #endif                          /* ! NO_CURSORCOLOR */
318     NULL,                       /* Color_pointer                  */
319     NULL,                       /* Color_border                   */
320 #ifndef NO_BOLD_UNDERLINE_REVERSE
321     NULL,                       /* Color_BD                       */
322     NULL,                       /* Color_UL                       */
323     NULL,                       /* Color_RV                       */
324 #endif                          /* ! NO_BOLD_UNDERLINE_REVERSE */
325 #ifdef OPTION_HC
326     NULL,
327 #endif
328 #ifdef KEEP_SCROLLCOLOR
329     COLOR_SCROLLBAR,
330     COLOR_SCROLLTROUGH,
331 #endif                          /* KEEP_SCROLLCOLOR */
332   };
333
334 const char *const xa_names[NUM_XA] =
335   {
336     "COMPOUND_TEXT",
337     "MULTIPLE",
338     "TARGETS",
339     "TEXT",
340     "TIMESTAMP",
341     "VT_SELECTION",
342     "INCR",
343     "WM_DELETE_WINDOW",
344 #ifdef TRANSPARENT
345     "_XROOTPMAP_ID",
346 #endif
347 #ifdef OFFIX_DND
348     "DndProtocol",
349     "DndSelection",
350 #endif
351     "CLIPBOARD"
352   };
353
354 bool
355 rxvt_term::init_vars()
356 {
357   PixColors = new rxvt_color [TOTAL_COLORS];
358   if (PixColors == NULL)
359     return false;
360
361 #if defined(XPM_BACKGROUND) || defined(TRANSPARENT)
362
363   TermWin.pixmap = None;
364 #endif
365 #ifdef UTMP_SUPPORT
366
367   next_utmp_action = SAVE;
368 #endif
369 #ifndef NO_SETOWNER_TTYDEV
370
371   next_tty_action = SAVE;
372 #endif
373
374   MEvent.time = CurrentTime;
375   MEvent.button = AnyButton;
376   Options = DEFAULT_OPTIONS;
377   want_refresh = 1;
378   cmd_pid = -1;
379   cmd_fd = tty_fd = Xfd = -1;
380   PrivateModes = SavedModes = PrivMode_Default;
381   TermWin.focus = 0;
382   TermWin.ncol = 80;
383   TermWin.nrow = 24;
384   TermWin.int_bwidth = INTERNALBORDERWIDTH;
385   TermWin.ext_bwidth = EXTERNALBORDERWIDTH;
386   TermWin.lineSpace = LINESPACE;
387   TermWin.saveLines = SAVELINES;
388   numPixColors = TOTAL_COLORS;
389 #ifndef NO_NEW_SELECTION
390
391   selection_style = NEW_SELECT;
392 #else
393
394   selection_style = OLD_SELECT;
395 #endif
396 #ifndef NO_BRIGHTCOLOR
397
398   colorfgbg = DEFAULT_RSTYLE;
399 #endif
400 #if defined (HOTKEY_CTRL) || defined (HOTKEY_META)
401
402   ks_bigfont = XK_greater;
403   ks_smallfont = XK_less;
404 #endif
405 #ifdef GREEK_SUPPORT
406
407   ks_greekmodeswith = GREEK_KEYBOARD_MODESWITCH;
408 #endif
409
410   refresh_limit = 1;
411   refresh_type = SLOW_REFRESH;
412   prev_nrow = prev_ncol = 0;
413 #ifdef MULTICHAR_SET
414 # ifdef MULTICHAR_ENCODING
415
416   encoding_method = MULTICHAR_ENCODING;
417 # endif
418
419   multichar_decode = rxvt_euc2jis;
420 #endif
421
422   oldcursor.row = oldcursor.col = -1;
423 #ifdef XPM_BACKGROUND
424   /*  bgPixmap.w = bgPixmap.h = 0; */
425   bgPixmap.x = bgPixmap.y = 50;
426   bgPixmap.pixmap = None;
427 #endif
428
429   last_bot = last_state = -1;
430 #ifdef MENUBAR
431
432   menu_readonly = 1;
433 # if !(MENUBAR_MAX > 1)
434
435   CurrentBar = &(BarList);
436 # endif                         /* (MENUBAR_MAX > 1) */
437 #endif
438
439   return true;
440 }
441
442 /* EXTPROTO */
443 void
444 rxvt_init_secondary (pR)
445 {
446   int             i;
447 #ifdef TTY_GID_SUPPORT
448   struct group   *gr = getgrnam ("tty");
449
450   if (gr)
451     {           /* change group ownership of tty to "tty" */
452       R->ttymode = S_IRUSR | S_IWUSR | S_IWGRP;
453       R->ttygid = gr->gr_gid;
454     }
455   else
456 #endif                          /* TTY_GID_SUPPORT */
457     {
458       R->ttymode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
459       R->ttygid = getgid ();
460     }
461
462 #if defined(HAVE_XSETLOCALE) || defined(HAVE_SETLOCALE)
463   R->locale = setlocale (LC_CTYPE, "");
464 #endif
465
466   /*
467    * Close all unused file descriptors
468    * We don't want them, we don't need them.
469    */
470   if ((i = open ("/dev/null", O_RDONLY)) < 0)
471     {
472       /* TODO: BOO HISS */
473       dup2 (STDERR_FILENO, STDIN_FILENO);
474     }
475   else if (i > STDIN_FILENO)
476     {
477       dup2 (i, STDIN_FILENO);
478       close (i);
479     }
480
481   dup2 (STDERR_FILENO, STDOUT_FILENO);
482 #if 0 // schmorp sayz closing filies is murder
483
484   for (i = STDERR_FILENO + 1; i < R->num_fds; i++)
485     {
486 #ifdef __sgi                    /* Alex Coventry says we need 4 & 7 too */
487       if (i == 4 || i == 7)
488         continue;
489 #endif
490
491       close(i);
492     }
493 #endif
494 }
495
496 /*----------------------------------------------------------------------*/
497 /* EXTPROTO */
498 const char    **
499 rxvt_init_resources (pR_ int argc, const char *const *argv)
500 {
501   int i, r_argc;
502   char *val;
503   const char **cmd_argv, **r_argv;
504   const char **rs;
505
506   /*
507    * Look for -exec option.  Find => split and make cmd_argv[] of command args
508    */
509   for (r_argc = 0; r_argc < argc; r_argc++)
510     if (!STRCMP (argv[r_argc], "-e") || !STRCMP(argv[r_argc], "-exec"))
511       break;
512   r_argv = (const char **)rxvt_malloc(sizeof(char *) * (r_argc + 1));
513
514   for (i = 0; i < r_argc; i++)
515     r_argv[i] = (const char *)argv[i];
516   r_argv[i] = NULL;
517   if (r_argc == argc)
518     cmd_argv = NULL;
519   else
520     {
521       cmd_argv = (const char **)rxvt_malloc(sizeof(char *) * (argc - r_argc));
522
523       for (i = 0; i < argc - r_argc - 1; i++)
524         cmd_argv[i] = (const char *)argv[i + r_argc + 1];
525       cmd_argv[i] = NULL;
526     }
527
528   /* clear all resources */
529   rs = R->rs;
530   for (i = 0; i < NUM_RESOURCES;)
531     rs[i++] = NULL;
532
533   rs[Rs_name] = rxvt_r_basename(argv[0]);
534   /*
535    * Open display, get options/resources and create the window
536    */
537   if ((rs[Rs_display_name] = getenv("DISPLAY")) == NULL)
538     rs[Rs_display_name] = ":0";
539
540   rxvt_get_options(aR_ r_argc, r_argv);
541   free(r_argv);
542
543 #ifdef LOCAL_X_IS_UNIX
544
545   if (rs[Rs_display_name][0] == ':')
546     {
547       val = rxvt_malloc(5 + STRLEN(rs[Rs_display_name]));
548       STRCPY(val, "unix");
549       STRCAT(val, rs[Rs_display_name]);
550       R->Xdisplay = XOpenDisplay(val);
551       free(val);
552     }
553 #endif
554
555   if (R->Xdisplay == NULL
556       && (R->Xdisplay = XOpenDisplay(rs[Rs_display_name])) == NULL)
557     {
558       rxvt_print_error("can't open display %s", rs[Rs_display_name]);
559       exit(EXIT_FAILURE);
560     }
561
562   rxvt_extract_resources(aR_ R->Xdisplay, rs[Rs_name]);
563
564   /*
565    * set any defaults not already set
566    */
567   if (cmd_argv && cmd_argv[0])
568     {
569       if (!rs[Rs_title])
570         rs[Rs_title] = rxvt_r_basename(cmd_argv[0]);
571       if (!rs[Rs_iconName])
572         rs[Rs_iconName] = rs[Rs_title];
573     }
574   else
575     {
576       if (!rs[Rs_title])
577         rs[Rs_title] = rs[Rs_name];
578       if (!rs[Rs_iconName])
579         rs[Rs_iconName] = rs[Rs_name];
580     }
581   if (rs[Rs_saveLines] && (i = atoi(rs[Rs_saveLines])) >= 0)
582     R->TermWin.saveLines = BOUND_POSITIVE_INT16(i);
583 #ifndef NO_FRILLS
584
585   if (rs[Rs_int_bwidth] && (i = atoi(rs[Rs_int_bwidth])) >= 0)
586     R->TermWin.int_bwidth = min(i, 100);    /* arbitrary limit */
587   if (rs[Rs_ext_bwidth] && (i = atoi(rs[Rs_ext_bwidth])) >= 0)
588     R->TermWin.ext_bwidth = min(i, 100);    /* arbitrary limit */
589 #endif
590 #ifndef NO_LINESPACE
591
592   if (rs[Rs_lineSpace] && (i = atoi(rs[Rs_lineSpace])) >= 0)
593     R->TermWin.lineSpace = min(i, 100);     /* arbitrary limit */
594 #endif
595
596 #ifdef POINTER_BLANK
597
598   if (rs[Rs_pointerBlankDelay] && (i = atoi(rs[Rs_pointerBlankDelay])) >= 0)
599     R->pointerBlankDelay = i;
600   else
601     R->pointerBlankDelay = 2;
602 #endif
603
604   /* no point having a scrollbar without having any scrollback! */
605   if (!R->TermWin.saveLines)
606     R->Options &= ~Opt_scrollBar;
607
608 #ifdef PRINTPIPE
609
610   if (!rs[Rs_print_pipe])
611     rs[Rs_print_pipe] = PRINTPIPE;
612 #endif
613
614   if (!rs[Rs_cutchars])
615     rs[Rs_cutchars] = CUTCHARS;
616 #ifdef ACS_ASCII
617
618   if (!rs[Rs_acs_chars])
619     rs[Rs_acs_chars] = ACS_CHARS;
620   if ((i = STRLEN(rs[Rs_acs_chars])) < 0x20)
621     {
622       val = rxvt_realloc((void *)rs[Rs_acs_chars], 0x20);
623       for (; i < 0x20; )
624         val[i] = ' ';
625       rs[Rs_acs_chars] = val;
626     }
627 #endif
628 #ifndef NO_BACKSPACE_KEY
629   if (!rs[Rs_backspace_key])
630 # ifdef DEFAULT_BACKSPACE
631
632     R->key_backspace = DEFAULT_BACKSPACE;
633 # else
634
635     R->key_backspace = "DEC";       /* can toggle between \010 or \177 */
636 # endif
637
638   else
639     {
640       val = STRDUP(rs[Rs_backspace_key]);
641       rxvt_Str_trim(val);
642       rxvt_Str_escaped(val);
643       R->key_backspace = val;
644     }
645 #endif
646 #ifndef NO_DELETE_KEY
647   if (!rs[Rs_delete_key])
648 # ifdef DEFAULT_DELETE
649
650     R->key_delete = DEFAULT_DELETE;
651 # else
652
653     R->key_delete = "\033[3~";
654 # endif
655
656   else
657     {
658       val = STRDUP(rs[Rs_delete_key]);
659       rxvt_Str_trim(val);
660       rxvt_Str_escaped(val);
661       R->key_delete = val;
662     }
663 #endif
664   if (rs[Rs_answerbackstring])
665     {
666       rxvt_Str_trim((char *)rs[Rs_answerbackstring]);
667       rxvt_Str_escaped((char *)rs[Rs_answerbackstring]);
668     }
669
670   if (rs[Rs_selectstyle])
671     {
672       if (STRNCASECMP(rs[Rs_selectstyle], "oldword", 7) == 0)
673         R->selection_style = OLD_WORD_SELECT;
674 #ifndef NO_OLD_SELECTION
675
676       else if (STRNCASECMP(rs[Rs_selectstyle], "old", 3) == 0)
677         R->selection_style = OLD_SELECT;
678 #endif
679
680     }
681
682 #ifdef HAVE_SCROLLBARS
683   rxvt_setup_scrollbar(aR_ rs[Rs_scrollBar_align], rs[Rs_scrollstyle],
684                        rs[Rs_scrollBar_thickness]);
685 #endif
686
687   R->TermWin.fontset = new rxvt_fontset (aR);
688   R->TermWin.fontset->populate (rs[Rs_font]);
689   R->TermWin.fwidth  = R->TermWin.fontset->base_font ()->width;
690   R->TermWin.fheight = R->TermWin.fontset->base_font ()->height;
691   R->TermWin.fbase   = R->TermWin.fontset->base_font ()->ascent;
692
693 #ifdef XTERM_REVERSE_VIDEO
694   /* this is how xterm implements reverseVideo */
695   if (R->Options & Opt_reverseVideo)
696     {
697       if (!rs[Rs_color + Color_fg])
698         rs[Rs_color + Color_fg] = def_colorName[Color_bg];
699       if (!rs[Rs_color + Color_bg])
700         rs[Rs_color + Color_bg] = def_colorName[Color_fg];
701     }
702 #endif
703
704   for (i = 0; i < NRS_COLORS; i++)
705     if (!rs[Rs_color + i])
706       rs[Rs_color + i] = def_colorName[i];
707
708 #ifndef XTERM_REVERSE_VIDEO
709   /* this is how we implement reverseVideo */
710   if (R->Options & Opt_reverseVideo)
711     SWAP_IT(rs[Rs_color + Color_fg], rs[Rs_color + Color_bg], const char *);
712 #endif
713
714   /* convenient aliases for setting fg/bg to colors */
715   rxvt_color_aliases(aR_ Color_fg);
716   rxvt_color_aliases(aR_ Color_bg);
717 #ifndef NO_CURSORCOLOR
718
719   rxvt_color_aliases(aR_ Color_cursor);
720   rxvt_color_aliases(aR_ Color_cursor2);
721 #endif                          /* NO_CURSORCOLOR */
722
723   rxvt_color_aliases(aR_ Color_pointer);
724   rxvt_color_aliases(aR_ Color_border);
725 #ifndef NO_BOLD_UNDERLINE_REVERSE
726
727   rxvt_color_aliases(aR_ Color_BD);
728   rxvt_color_aliases(aR_ Color_UL);
729   rxvt_color_aliases(aR_ Color_RV);
730 #endif                          /* ! NO_BOLD_UNDERLINE_REVERSE */
731
732   return cmd_argv;
733 }
734
735 /*----------------------------------------------------------------------*/
736 /* EXTPROTO */
737 void
738 rxvt_init_env(pR)
739 {
740   int             i;
741   unsigned int    u;
742   char           *val;
743
744 #ifdef DISPLAY_IS_IP
745   /* Fixup display_name for export over pty to any interested terminal
746    * clients via "ESC[7n" (e.g. shells).  Note we use the pure IP number
747    * (for the first non-loopback interface) that we get from
748    * rxvt_network_display().  This is more "name-resolution-portable", if you
749    * will, and probably allows for faster x-client startup if your name
750    * server is beyond a slow link or overloaded at client startup.  Of
751    * course that only helps the shell's child processes, not us.
752    *
753    * Giving out the display_name also affords a potential security hole
754    */
755   val = rxvt_network_display(R->rs[Rs_display_name]);
756   R->rs[Rs_display_name] = (const char *)val;
757   if (val == NULL)
758 #endif                          /* DISPLAY_IS_IP */
759
760     val = XDisplayString(R->Xdisplay);
761   if (R->rs[Rs_display_name] == NULL)
762     R->rs[Rs_display_name] = val;   /* use broken `:0' value */
763
764   i = STRLEN(val);
765   R->env_display = (char *)rxvt_malloc((i + 9) * sizeof(char));
766
767   sprintf(R->env_display, "DISPLAY=%s", val);
768
769   /* avoiding the math library:
770    * i = (int)(ceil(log10((unsigned int)R->TermWin.parent[0]))) */
771   for (i = 0, u = (unsigned int)R->TermWin.parent[0]; u; u /= 10, i++)
772     ;
773   MAX_IT(i, 1);
774   R->env_windowid = (char *)rxvt_malloc((i + 10) * sizeof(char));
775
776   sprintf(R->env_windowid, "WINDOWID=%u",
777           (unsigned int)R->TermWin.parent[0]);
778
779   /* add entries to the environment:
780    * @ DISPLAY:   in case we started with -display
781    * @ WINDOWID:  X window id number of the window
782    * @ COLORTERM: terminal sub-name and also indicates its color
783    * @ TERM:      terminal name
784    * @ TERMINFO:  path to terminfo directory
785    */
786   putenv(R->env_display);
787   putenv(R->env_windowid);
788 #ifdef RXVT_TERMINFO
789
790   putenv("TERMINFO=" RXVT_TERMINFO);
791 #endif
792
793   if (XDEPTH <= 2)
794     putenv("COLORTERM=" COLORTERMENV "-mono");
795   else
796     putenv("COLORTERM=" COLORTERMENVFULL);
797   if (R->rs[Rs_term_name] != NULL)
798     {
799       R->env_term = (char *)rxvt_malloc((STRLEN(R->rs[Rs_term_name]) + 6) * sizeof(char));
800       sprintf(R->env_term, "TERM=%s", R->rs[Rs_term_name]);
801       putenv(R->env_term);
802     }
803   else
804     putenv("TERM=" TERMENV);
805
806 #ifdef HAVE_UNSETENV
807   /* avoid passing old settings and confusing term size */
808   unsetenv("LINES");
809   unsetenv("COLUMNS");
810   unsetenv("TERMCAP");        /* terminfo should be okay */
811 #endif                          /* HAVE_UNSETENV */
812 }
813
814 /*----------------------------------------------------------------------*/
815 /*
816  * This is more or less stolen straight from XFree86 xterm.
817  * This should support all European type languages.
818  */
819 /* EXTPROTO */
820 void
821 rxvt_init_xlocale(pR)
822 {
823 #ifdef USE_XIM
824   if (R->locale == NULL)
825     rxvt_print_error("Setting locale failed.");
826   else
827     {
828       Atom            wmlocale;
829
830       wmlocale = XInternAtom(R->Xdisplay, "WM_LOCALE_NAME", False);
831       XChangeProperty(R->Xdisplay, R->TermWin.parent[0], wmlocale,
832                       XA_STRING, 8, PropModeReplace,
833                       (unsigned char *)R->locale, STRLEN(R->locale));
834
835       if (XSupportsLocale() != True)
836         {
837           rxvt_print_error("The locale is not supported by Xlib");
838           return;
839         }
840       rxvt_setTermFontSet(aR_ 0);
841
842       /* see if we can connect yet */
843       rxvt_IMInstantiateCallback(R->Xdisplay, NULL, NULL);
844
845       /* To avoid Segmentation Fault in C locale: Solaris only? */
846       if (STRCMP(R->locale, "C"))
847         XRegisterIMInstantiateCallback(R->Xdisplay, NULL, NULL, NULL,
848                                        rxvt_IMInstantiateCallback, NULL);
849     }
850 #endif
851 }
852
853 /*----------------------------------------------------------------------*/
854 /* EXTPROTO */
855 void
856 rxvt_init_command(pR_ const char *const *argv)
857 {
858   /*
859    * Initialize the command connection.
860    * This should be called after the X server connection is established.
861    */
862   int i;
863
864   for (i = 0; i < NUM_XA; i++)
865     R->xa[i] = XInternAtom(R->Xdisplay, xa_names[i], False);
866
867   /* Enable delete window protocol */
868   XSetWMProtocols(R->Xdisplay, R->TermWin.parent[0],
869                   &(R->xa[XA_WMDELETEWINDOW]), 1);
870
871 #ifdef USING_W11LIB
872   /* enable W11 callbacks */
873   W11AddEventHandler(R->Xdisplay, rxvt_W11_process_x_event);
874 #endif
875
876 #ifdef META8_OPTION
877
878   R->meta_char = (R->Options & Opt_meta8 ? 0x80 : C0_ESC);
879 #endif
880
881   rxvt_get_ourmods(aR);
882
883   if (!(R->Options & Opt_scrollTtyOutput))
884     R->PrivateModes |= PrivMode_TtyOutputInh;
885   if (R->Options & Opt_scrollTtyKeypress)
886     R->PrivateModes |= PrivMode_Keypress;
887   if (!(R->Options & Opt_jumpScroll))
888     R->PrivateModes |= PrivMode_smoothScroll;
889 #ifndef NO_BACKSPACE_KEY
890
891   if (STRCMP(R->key_backspace, "DEC") == 0)
892     R->PrivateModes |= PrivMode_HaveBackSpace;
893 #endif
894   /* add value for scrollBar */
895   if (scrollbar_visible(R))
896     {
897       R->PrivateModes |= PrivMode_scrollBar;
898       R->SavedModes |= PrivMode_scrollBar;
899     }
900   if (menubar_visible(R))
901     {
902       R->PrivateModes |= PrivMode_menuBar;
903       R->SavedModes |= PrivMode_menuBar;
904     }
905 #ifdef GREEK_SUPPORT
906   greek_init();
907 #endif
908
909   R->Xfd = XConnectionNumber (R->Xdisplay);
910
911 #ifdef CURSOR_BLINK
912
913   if (R->Options & Opt_cursorBlink)
914     (void)gettimeofday(&R->lastcursorchange, NULL);
915 #endif
916
917   if ((R->cmd_fd = rxvt_run_command (aR_ argv)) < 0)
918     {
919       rxvt_print_error ("aborting");
920       exit (EXIT_FAILURE);
921     }
922 }
923
924 /*----------------------------------------------------------------------*/
925 /* INTPROTO */
926 void
927 rxvt_Get_Colours(pR)
928 {
929   int             i;
930
931   for (i = 0; i < (XDEPTH <= 2 ? 2 : NRS_COLORS); i++)
932     {
933       rxvt_color          xcol;
934
935       if (!R->rs[Rs_color + i])
936         continue;
937
938       if (!rxvt_rXParseAllocColor(aR_ &xcol, R->rs[Rs_color + i]))
939         {
940 #ifndef XTERM_REVERSE_VIDEO
941           if (i < 2 && (R->Options & Opt_reverseVideo))
942             {
943               R->rs[Rs_color + i] = def_colorName[!i];
944             }
945           else
946 #endif
947
948             R->rs[Rs_color + i] = def_colorName[i];
949           if (!R->rs[Rs_color + i])
950             continue;
951           if (!rxvt_rXParseAllocColor(aR_ &xcol, R->rs[Rs_color + i]))
952             {
953               switch (i)
954                 {
955                 case Color_fg:
956                 case Color_bg:
957                   /* fatal: need bg/fg color */
958                   rxvt_print_error("aborting");
959                   exit(EXIT_FAILURE);
960                   /* NOTREACHED */
961                   break;
962 #ifndef NO_CURSORCOLOR
963
964                 case Color_cursor2:
965                   xcol = R->PixColors[Color_fg];
966                   break;
967 #endif                          /* ! NO_CURSORCOLOR */
968
969                 case Color_pointer:
970                   xcol = R->PixColors[Color_fg];
971                   break;
972                 default:
973                   xcol = R->PixColors[Color_bg];      /* None */
974                   break;
975                 }
976             }
977         }
978       R->PixColors[i] = xcol;
979       SET_PIXCOLOR(R, i);
980     }
981
982   if (XDEPTH <= 2 || !R->rs[Rs_color + Color_pointer])
983     R->PixColors[Color_pointer] = R->PixColors[Color_fg];
984   if (XDEPTH <= 2 || !R->rs[Rs_color + Color_border])
985     R->PixColors[Color_border] = R->PixColors[Color_fg];
986
987   /*
988    * get scrollBar/menuBar shadow colors
989    *
990    * The calculations of topShadow/bottomShadow values are adapted
991    * from the fvwm window manager.
992    */
993 #ifdef KEEP_SCROLLCOLOR
994
995   if (XDEPTH <= 2)
996     {  /* Monochrome */
997       R->PixColors[Color_scroll] = R->PixColors[Color_fg];
998       R->PixColors[Color_topShadow] = R->PixColors[Color_bg];
999       R->PixColors[Color_bottomShadow] = R->PixColors[Color_bg];
1000     }
1001   else
1002     {
1003       rxvt_color          xcol[3];
1004       /* xcol[0] == white
1005        * xcol[1] == top shadow
1006        * xcol[2] == bot shadow */
1007
1008       xcol[1] = R->PixColors[Color_scroll];
1009 # ifdef PREFER_24BIT
1010
1011       xcol[0].set (r, -1, -1, -1);
1012       /*        XFreeColors(R->Xdisplay, XCMAP, &(xcol[0].pixel), 1, ~0); */
1013 # else
1014
1015       xcol[0].set (WhitePixel(R->Xdisplay, Xscreen));
1016 # endif
1017
1018       unsigned short R1, G1, B1, R0, G0, B0;
1019
1020       xcol[0].get (r, R0, G0, B0);
1021       xcol[1].get (r, R1, G1, B1);
1022
1023       /* bottomShadowColor */
1024       if (!xcol[2].set (aR_ R1 / 2, G1 / 2, B1 / 2))
1025         xcol[2] = R->PixColors[Color_Black];
1026
1027       R->PixColors[Color_bottomShadow] = xcol[2];
1028
1029       /* topShadowColor */
1030       if (!xcol[1].set (aR_
1031                         min (R0, max (R0 / 5, R1) * 7 / 5),
1032                         min (G0, max (G0 / 5, G1) * 7 / 5),
1033                         min (B0, max (B0 / 5, B1) * 7 / 5)))
1034         xcol[1] = R->PixColors[Color_White];
1035
1036       R->PixColors[Color_topShadow] = xcol[1];
1037     }
1038 #endif                          /* KEEP_SCROLLCOLOR */
1039 }
1040
1041 /*----------------------------------------------------------------------*/
1042 /* color aliases, fg/bg bright-bold */
1043 /* INTPROTO */
1044 void
1045 rxvt_color_aliases(pR_ int idx)
1046 {
1047   if (R->rs[Rs_color + idx] && isdigit(*(R->rs[Rs_color + idx])))
1048     {
1049       int             i = atoi(R->rs[Rs_color + idx]);
1050
1051       if (i >= 8 && i <= 15)
1052         {        /* bright colors */
1053           i -= 8;
1054 #ifndef NO_BRIGHTCOLOR
1055
1056           R->rs[Rs_color + idx] = R->rs[Rs_color + minBrightCOLOR + i];
1057           return;
1058 #endif
1059
1060         }
1061       if (i >= 0 && i <= 7)   /* normal colors */
1062         R->rs[Rs_color + idx] = R->rs[Rs_color + minCOLOR + i];
1063     }
1064 }
1065
1066 /*----------------------------------------------------------------------*/
1067 /*
1068  * Probe the modifier keymap to get the Meta (Alt) and Num_Lock settings
1069  * Use resource ``modifier'' to override the Meta modifier
1070  */
1071 /* INTPROTO */
1072 void
1073 rxvt_get_ourmods(pR)
1074 {
1075   int             i, j, k;
1076   int             requestedmeta, realmeta, realalt;
1077   const char     *cm, *rsmod;
1078   XModifierKeymap *map;
1079   KeyCode        *kc;
1080   const unsigned int modmasks[] =
1081     {
1082       Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
1083     };
1084
1085   requestedmeta = realmeta = realalt = 0;
1086   rsmod = R->rs[Rs_modifier];
1087   if (rsmod
1088       && STRCASECMP(rsmod, "mod1") >= 0 && STRCASECMP(rsmod, "mod5") <= 0)
1089     requestedmeta = rsmod[3] - '0';
1090
1091   map = XGetModifierMapping(R->Xdisplay);
1092   kc = map->modifiermap;
1093   for (i = 1; i < 6; i++)
1094     {
1095       k = (i + 2) * map->max_keypermod;       /* skip shift/lock/control */
1096       for (j = map->max_keypermod; j--; k++)
1097         {
1098           if (kc[k] == 0)
1099             break;
1100           switch (XKeycodeToKeysym(R->Xdisplay, kc[k], 0))
1101             {
1102             case XK_Num_Lock:
1103               R->ModNumLockMask = modmasks[i - 1];
1104               /* FALLTHROUGH */
1105             default:
1106               continue;       /* for(;;) */
1107             case XK_Meta_L:
1108             case XK_Meta_R:
1109               cm = "meta";
1110               realmeta = i;
1111               break;
1112             case XK_Alt_L:
1113             case XK_Alt_R:
1114               cm = "alt";
1115               realalt = i;
1116               break;
1117             case XK_Super_L:
1118             case XK_Super_R:
1119               cm = "super";
1120               break;
1121             case XK_Hyper_L:
1122             case XK_Hyper_R:
1123               cm = "hyper";
1124               break;
1125             }
1126           if (rsmod && STRNCASECMP(rsmod, cm, STRLEN(cm)) == 0)
1127             requestedmeta = i;
1128         }
1129     }
1130   XFreeModifiermap(map);
1131   i = (requestedmeta ? requestedmeta
1132        : (realmeta ? realmeta
1133           : (realalt ? realalt : 0)));
1134   if (i)
1135     R->ModMetaMask = modmasks[i - 1];
1136 }
1137
1138 /*----------------------------------------------------------------------*/
1139 /* rxvt_Create_Windows() - Open and map the window */
1140 /* EXTPROTO */
1141 void
1142 rxvt_Create_Windows(pR_ int argc, const char *const *argv)
1143 {
1144   XClassHint      classHint;
1145   XWMHints        wmHint;
1146   XGCValues       gcvalue;
1147   long            vt_emask;
1148
1149 #ifdef PREFER_24BIT
1150
1151   XSetWindowAttributes attributes;
1152   XWindowAttributes gattr;
1153
1154   XCMAP = DefaultColormap(R->Xdisplay, Xscreen);
1155   XVISUAL = DefaultVisual(R->Xdisplay, Xscreen);
1156
1157   if (R->Options & Opt_transparent)
1158     {
1159       XGetWindowAttributes(R->Xdisplay, RootWindow(R->Xdisplay, Xscreen),
1160                            &gattr);
1161       XDEPTH = gattr.depth;
1162     }
1163   else
1164     {
1165       XDEPTH = DefaultDepth(R->Xdisplay, Xscreen);
1166       /*
1167        * If depth is not 24, look for a 24bit visual.
1168        */
1169       if (XDEPTH != 24)
1170         {
1171           XVisualInfo     vinfo;
1172
1173           if (XMatchVisualInfo(R->Xdisplay, Xscreen, 24, TrueColor, &vinfo))
1174             {
1175               XDEPTH = 24;
1176               XVISUAL = vinfo.visual;
1177               XCMAP = XCreateColormap(R->Xdisplay,
1178                                       RootWindow(R->Xdisplay, Xscreen),
1179                                       XVISUAL, AllocNone);
1180             }
1181         }
1182     }
1183 #endif
1184
1185   /* grab colors before netscape does */
1186   rxvt_Get_Colours(aR);
1187
1188   rxvt_change_font(aR_ 1, NULL);
1189   rxvt_window_calc(aR_ 0, 0);
1190   R->old_width = R->szHint.width;
1191   R->old_height = R->szHint.height;
1192
1193   /* parent window - reverse video so we can see placement errors
1194    * sub-window placement & size in rxvt_resize_subwindows()
1195    */
1196
1197 #ifdef PREFER_24BIT
1198
1199   attributes.background_pixel = R->PixColors[Color_fg];
1200   attributes.border_pixel = R->PixColors[Color_border];
1201   attributes.colormap = XCMAP;
1202   R->TermWin.parent[0] = XCreateWindow(R->Xdisplay, Xroot,
1203                                        R->szHint.x, R->szHint.y,
1204                                        R->szHint.width, R->szHint.height,
1205                                        R->TermWin.ext_bwidth,
1206                                        XDEPTH, InputOutput,
1207                                        XVISUAL,
1208                                        CWBackPixel | CWBorderPixel
1209                                        | CWColormap, &attributes);
1210 #else
1211
1212   R->TermWin.parent[0] = XCreateSimpleWindow(R->Xdisplay, Xroot,
1213                          R->szHint.x, R->szHint.y,
1214                          R->szHint.width,
1215                          R->szHint.height,
1216                          R->TermWin.ext_bwidth,
1217                          R->PixColors[Color_border],
1218                          R->PixColors[Color_fg]);
1219 #endif
1220
1221   rxvt_xterm_seq(aR_ XTerm_title, R->rs[Rs_title], CHAR_ST);
1222   rxvt_xterm_seq(aR_ XTerm_iconName, R->rs[Rs_iconName], CHAR_ST);
1223
1224   classHint.res_name = (char *)R->rs[Rs_name];
1225   classHint.res_class = (char *)APL_CLASS;
1226
1227   wmHint.flags = (InputHint | StateHint | WindowGroupHint);
1228   wmHint.input = True;
1229   wmHint.initial_state = (R->Options & Opt_iconic ? IconicState
1230                           : NormalState);
1231   wmHint.window_group = R->TermWin.parent[0];
1232
1233   XSetWMProperties(R->Xdisplay, R->TermWin.parent[0], NULL, NULL,
1234                    (char **)argv, argc, &R->szHint, &wmHint, &classHint);
1235   XSelectInput(R->Xdisplay, R->TermWin.parent[0],
1236                (KeyPressMask
1237 #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
1238                 | KeyReleaseMask
1239 #endif
1240                 | FocusChangeMask | VisibilityChangeMask
1241                 | StructureNotifyMask));
1242
1243   /* vt cursor: Black-on-White is standard, but this is more popular */
1244   R->TermWin_cursor = XCreateFontCursor(R->Xdisplay, XC_xterm);
1245
1246 #if defined(HAVE_SCROLLBARS) || defined(MENUBAR)
1247   /* cursor (menuBar/scrollBar): Black-on-White */
1248   R->leftptr_cursor = XCreateFontCursor(R->Xdisplay, XC_left_ptr);
1249 #endif
1250
1251 #ifdef POINTER_BLANK
1252
1253   {
1254     XColor blackcolour;
1255     blackcolour.red   = 0;
1256     blackcolour.green = 0;
1257     blackcolour.blue  = 0;
1258     Font f = XLoadFont (R->Xdisplay, "fixed");
1259     R->blank_cursor = XCreateGlyphCursor (R->Xdisplay, f, f, ' ', ' ',
1260                                           &blackcolour, &blackcolour);
1261     XUnloadFont (R->Xdisplay, f);
1262   }
1263 #endif
1264
1265   /* the vt window */
1266   R->TermWin.vt = XCreateSimpleWindow(R->Xdisplay, R->TermWin.parent[0],
1267                                       R->window_vt_x, R->window_vt_y,
1268                                       TermWin_TotalWidth(),
1269                                       TermWin_TotalHeight(),
1270                                       0,
1271                                       R->PixColors[Color_fg],
1272                                       R->PixColors[Color_bg]);
1273 #ifdef DEBUG_X
1274
1275   XStoreName(R->Xdisplay, R->TermWin.vt, "vt window");
1276 #endif
1277
1278   R->pointer_unblank ();
1279
1280   vt_emask = (ExposureMask | ButtonPressMask | ButtonReleaseMask
1281               | PropertyChangeMask);
1282 #ifdef POINTER_BLANK
1283
1284   if ((R->Options & Opt_pointerBlank))
1285     vt_emask |= PointerMotionMask;
1286   else
1287 #endif
1288
1289     vt_emask |= (Button1MotionMask | Button3MotionMask);
1290   XSelectInput(R->Xdisplay, R->TermWin.vt, vt_emask);
1291
1292 #if defined(MENUBAR) && (MENUBAR_MAX > 1)
1293
1294   if (menuBar_height())
1295     {
1296       R->menuBar.win = XCreateSimpleWindow(R->Xdisplay, R->TermWin.parent[0],
1297                                            R->window_vt_x, 0,
1298                                            TermWin_TotalWidth(),
1299                                            menuBar_TotalHeight(),
1300                                            0,
1301                                            R->PixColors[Color_fg],
1302                                            R->PixColors[Color_scroll]);
1303 #ifdef DEBUG_X
1304
1305       XStoreName(R->Xdisplay, R->menuBar.win, "menubar");
1306 #endif
1307
1308       XDefineCursor(R->Xdisplay, R->menuBar.win, R->pointer_leftptr);
1309       XSelectInput(R->Xdisplay, R->menuBar.win,
1310                    (ExposureMask | ButtonPressMask | ButtonReleaseMask
1311                     | Button1MotionMask));
1312     }
1313 #endif
1314 #ifdef XPM_BACKGROUND
1315   if (R->rs[Rs_backgroundPixmap] != NULL
1316       && !(R->Options & Opt_transparent))
1317     {
1318       const char     *p = R->rs[Rs_backgroundPixmap];
1319
1320       if ((p = STRCHR(p, ';')) != NULL)
1321         {
1322           p++;
1323           rxvt_scale_pixmap(aR_ p);
1324         }
1325       rxvt_set_bgPixmap(aR_ R->rs[Rs_backgroundPixmap]);
1326       rxvt_scr_touch(aR_ True);
1327     }
1328 #endif
1329
1330   /* graphics context for the vt window */
1331   gcvalue.foreground = R->PixColors[Color_fg];
1332   gcvalue.background = R->PixColors[Color_bg];
1333   gcvalue.graphics_exposures = 1;
1334   R->TermWin.gc = XCreateGC(R->Xdisplay, R->TermWin.vt,
1335                             GCForeground | GCBackground
1336                             | GCGraphicsExposures, &gcvalue);
1337
1338 #if defined(MENUBAR) || defined(RXVT_SCROLLBAR)
1339
1340   gcvalue.foreground = R->PixColors[Color_topShadow];
1341   R->topShadowGC = XCreateGC(R->Xdisplay, R->TermWin.vt,
1342                              GCForeground, &gcvalue);
1343   gcvalue.foreground = R->PixColors[Color_bottomShadow];
1344   R->botShadowGC = XCreateGC(R->Xdisplay, R->TermWin.vt,
1345                              GCForeground, &gcvalue);
1346   gcvalue.foreground = R->PixColors[(XDEPTH <= 2 ? Color_fg
1347                                      : Color_scroll)];
1348   R->scrollbarGC = XCreateGC(R->Xdisplay, R->TermWin.vt,
1349                              GCForeground, &gcvalue);
1350 #endif
1351 }
1352
1353 /*----------------------------------------------------------------------*/
1354 /*
1355  * Run the command in a subprocess and return a file descriptor for the
1356  * master end of the pseudo-teletype pair with the command talking to
1357  * the slave.
1358  */
1359 /* INTPROTO */
1360 int
1361 rxvt_run_command(pR_ const char *const *argv)
1362 {
1363   int cfd, er;
1364
1365   /* get master (pty) */
1366   if ((cfd = rxvt_get_pty (&(R->tty_fd), &(R->ttydev))) < 0)
1367     {
1368       rxvt_print_error("can't open pseudo-tty");
1369       return -1;
1370     }
1371
1372 #ifdef FD_SETSIZE
1373   if (R->Xfd > FD_SETSIZE || cfd > FD_SETSIZE)
1374     {
1375       rxvt_print_error("fd too high: %d max", FD_SETSIZE);
1376       rxvt_clean_exit();
1377       exit(EXIT_FAILURE);
1378     }
1379 #endif
1380
1381   fcntl (cfd, F_SETFL, O_NONBLOCK);
1382
1383   /* get slave (tty) */
1384   if (R->tty_fd < 0)
1385     {
1386 #ifndef NO_SETOWNER_TTYDEV
1387       rxvt_privileged_ttydev (aR_ SAVE);
1388 #endif
1389
1390       if ((R->tty_fd = rxvt_get_tty (R->ttydev)) < 0)
1391         {
1392           close(cfd);
1393           rxvt_print_error("can't open slave tty %s", R->ttydev);
1394           return -1;
1395         }
1396     }
1397 #ifndef NO_BACKSPACE_KEY
1398   if (R->key_backspace[0] && !R->key_backspace[1])
1399     er = R->key_backspace[0];
1400   else if (STRCMP(R->key_backspace, "DEC") == 0)
1401     er = '\177';            /* the initial state anyway */
1402   else
1403 #endif
1404
1405     er = -1;
1406
1407   rxvt_get_ttymode (&(R->tio), er);
1408
1409 #ifndef __QNX__
1410   /* spin off the command interpreter */
1411   switch (R->cmd_pid = fork ())
1412     {
1413     case -1:
1414       rxvt_print_error("can't fork");
1415       return -1;
1416     case 0:
1417       close (cfd);             /* only keep R->tty_fd and STDERR open */
1418       close (R->Xfd);
1419       if (rxvt_control_tty (R->tty_fd, R->ttydev) < 0)
1420         rxvt_print_error ("could not obtain control of tty");
1421       else
1422         {
1423           /* Reopen stdin, stdout and stderr over the tty file descriptor */
1424           dup2 (R->tty_fd, STDIN_FILENO);
1425           dup2 (R->tty_fd, STDOUT_FILENO);
1426           dup2 (R->tty_fd, STDERR_FILENO);
1427
1428           if (R->tty_fd > 2)
1429             close (R->tty_fd);
1430
1431           rxvt_run_child (aR_ argv);
1432         }
1433       exit (EXIT_FAILURE);
1434       /* NOTREACHED */
1435     default:
1436       {
1437 #if defined(HAVE_STRUCT_UTMP) && defined(HAVE_TTYSLOT)
1438         int fdstdin;
1439
1440         fdstdin = dup (STDIN_FILENO);
1441         dup2 (R->tty_fd, STDIN_FILENO);
1442 #endif
1443
1444         rxvt_privileged_utmp (aR_ SAVE);
1445 #if defined(HAVE_STRUCT_UTMP) && defined(HAVE_TTYSLOT)
1446
1447         dup2 (fdstdin, STDIN_FILENO);
1448         close (fdstdin);
1449 #endif
1450
1451       }
1452       close (R->tty_fd);       /* keep STDERR_FILENO, R->cmd_fd, R->Xfd open */
1453       break;
1454     }
1455 #else                           /* __QNX__ uses qnxspawn() */
1456   fchmod (R->tty_fd, 0622);
1457   fcntl (R->tty_fd, F_SETFD, FD_CLOEXEC);
1458   fcntl (cfd, F_SETFD, FD_CLOEXEC);
1459
1460   if (rxvt_run_child (aR_ argv) == -1)
1461     exit (EXIT_FAILURE);
1462 #endif
1463
1464   return cfd;
1465 }
1466
1467 /* ------------------------------------------------------------------------- *
1468  *                          CHILD PROCESS OPERATIONS                         *
1469  * ------------------------------------------------------------------------- */
1470 /*
1471  * The only open file descriptor is the slave tty - so no error messages.
1472  * returns are fatal
1473  */
1474 /* INTPROTO */
1475 int
1476 rxvt_run_child(pR_ const char *const *argv)
1477 {
1478   char *login;
1479
1480   SET_TTYMODE (STDIN_FILENO, &(R->tio));       /* init terminal attributes */
1481
1482   if (R->Options & Opt_console)
1483     {     /* be virtual console, fail silently */
1484 #ifdef TIOCCONS
1485       unsigned int on = 1;
1486
1487       ioctl (STDIN_FILENO, TIOCCONS, &on);
1488 #elif defined (SRIOCSREDIR)
1489
1490       int fd;
1491
1492       fd = open (CONSOLE, O_WRONLY, 0);
1493       if (fd >= 0)
1494         {
1495           if (ioctl (fd, SRIOCSREDIR, NULL) < 0)
1496             close (fd);
1497         }
1498 #endif                          /* SRIOCSREDIR */
1499
1500     }
1501
1502   /* reset signals and spin off the command interpreter */
1503   signal (SIGINT,  SIG_DFL);
1504   signal (SIGQUIT, SIG_DFL);
1505   signal (SIGCHLD, SIG_DFL);
1506   /*
1507    * mimick login's behavior by disabling the job control signals
1508    * a shell that wants them can turn them back on
1509    */
1510 #ifdef SIGTSTP
1511
1512   signal (SIGTSTP, SIG_IGN);
1513   signal (SIGTTIN, SIG_IGN);
1514   signal (SIGTTOU, SIG_IGN);
1515 #endif                          /* SIGTSTP */
1516
1517   /* set window size */
1518   struct winsize ws;
1519
1520   ws.ws_col = R->TermWin.ncol;
1521   ws.ws_row = R->TermWin.nrow;
1522   ws.ws_xpixel = ws.ws_ypixel = 0;
1523   (void)ioctl (STDIN_FILENO, TIOCSWINSZ, &ws);
1524
1525   // unblock signals (signals are blocked by iom.C
1526   sigset_t ss;
1527   sigemptyset (&ss);
1528   sigprocmask (SIG_SETMASK, &ss, 0);
1529
1530 #ifndef __QNX__
1531   /* command interpreter path */
1532   if (argv != NULL)
1533     {
1534 # ifdef DEBUG_CMD
1535       int             i;
1536
1537       for (i = 0; argv[i]; i++)
1538         fprintf(stderr, "argv [%d] = \"%s\"\n", i, argv[i]);
1539 # endif
1540
1541       execvp(argv[0], (char *const *)argv);
1542       /* no error message: STDERR is closed! */
1543     }
1544   else
1545     {
1546       const char     *argv0, *shell;
1547
1548       if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
1549         shell = "/bin/sh";
1550
1551       argv0 = (const char *)rxvt_r_basename(shell);
1552       if (R->Options & Opt_loginShell)
1553         {
1554           login = (char *)rxvt_malloc((STRLEN(argv0) + 2) * sizeof(char));
1555
1556           login[0] = '-';
1557           STRCPY(&login[1], argv0);
1558           argv0 = login;
1559         }
1560       execlp(shell, argv0, NULL);
1561       /* no error message: STDERR is closed! */
1562     }
1563 #else                           /* __QNX__ uses qnxspawn() */
1564   {
1565     char            iov_a[10] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
1566     char           *command = NULL, fullcommand[_MAX_PATH];
1567     char          **arg_v, *arg_a[2] = { NULL, NULL };
1568
1569     if (argv != NULL)
1570       {
1571         if (access(argv[0], X_OK) == -1)
1572           {
1573             if (STRCHR(argv[0], '/') == NULL)
1574               {
1575                 searchenv(argv[0], "PATH", fullcommand);
1576                 if (fullcommand[0] != '\0')
1577                   command = fullcommand;
1578               }
1579             if (access(command, X_OK) == -1)
1580               return -1;
1581           }
1582         else
1583           command = argv[0];
1584         arg_v = argv;
1585       }
1586     else
1587       {
1588         if ((command = getenv("SHELL")) == NULL || *command == '\0')
1589           command = "/bin/sh";
1590
1591         arg_a[0] = my_basename(command);
1592         if (R->Options & Opt_loginShell)
1593           {
1594             login = rxvt_malloc((STRLEN(arg_a[0]) + 2) * sizeof(char));
1595
1596             login[0] = '-';
1597             STRCPY(&login[1], arg_a[0]);
1598             arg_a[0] = login;
1599           }
1600         arg_v = arg_a;
1601       }
1602     iov_a[0] = iov_a[1] = iov_a[2] = R->tty_fd;
1603     R->cmd_pid = qnx_spawn(0, 0, 0, -1, -1,
1604                            _SPAWN_SETSID | _SPAWN_TCSETPGRP,
1605                            command, arg_v, environ, iov_a, 0);
1606     if (login)
1607       free(login);
1608     close(R->tty_fd);
1609     return R->cmd_fd;
1610   }
1611 #endif
1612   return -1;
1613 }
1614
1615 /* ------------------------------------------------------------------------- *
1616  *                            GET TTY CURRENT STATE                          *
1617  * ------------------------------------------------------------------------- */
1618 /* rxvt_get_ttymode() */
1619 /* INTPROTO */
1620 void
1621 rxvt_get_ttymode(ttymode_t *tio, int erase)
1622 {
1623 #ifdef HAVE_TERMIOS_H
1624   /*
1625    * standard System V termios interface
1626    */
1627   if (GET_TERMIOS(STDIN_FILENO, tio) < 0)
1628     {
1629       /* return error - use system defaults */
1630       tio->c_cc[VINTR] = CINTR;
1631       tio->c_cc[VQUIT] = CQUIT;
1632       tio->c_cc[VERASE] = CERASE;
1633       tio->c_cc[VKILL] = CKILL;
1634       tio->c_cc[VSTART] = CSTART;
1635       tio->c_cc[VSTOP] = CSTOP;
1636       tio->c_cc[VSUSP] = CSUSP;
1637 # ifdef VDSUSP
1638
1639       tio->c_cc[VDSUSP] = CDSUSP;
1640 # endif
1641 # ifdef VREPRINT
1642
1643       tio->c_cc[VREPRINT] = CRPRNT;
1644 # endif
1645 # ifdef VDISCRD
1646
1647       tio->c_cc[VDISCRD] = CFLUSH;
1648 # endif
1649 # ifdef VWERSE
1650
1651       tio->c_cc[VWERSE] = CWERASE;
1652 # endif
1653 # ifdef VLNEXT
1654
1655       tio->c_cc[VLNEXT] = CLNEXT;
1656 # endif
1657
1658     }
1659   tio->c_cc[VEOF] = CEOF;
1660   tio->c_cc[VEOL] = VDISABLE;
1661 # ifdef VEOL2
1662
1663   tio->c_cc[VEOL2] = VDISABLE;
1664 # endif
1665 # ifdef VSWTC
1666
1667   tio->c_cc[VSWTC] = VDISABLE;
1668 # endif
1669 # ifdef VSWTCH
1670
1671   tio->c_cc[VSWTCH] = VDISABLE;
1672 # endif
1673 # if VMIN != VEOF
1674
1675   tio->c_cc[VMIN] = 1;
1676 # endif
1677 # if VTIME != VEOL
1678
1679   tio->c_cc[VTIME] = 0;
1680 # endif
1681
1682   if (erase != -1)
1683     tio->c_cc[VERASE] = (char)erase;
1684
1685   /* input modes */
1686   tio->c_iflag = (BRKINT | IGNPAR | ICRNL
1687 # ifdef IMAXBEL
1688                   | IMAXBEL
1689 # endif
1690                   | IXON);
1691
1692   /* output modes */
1693   tio->c_oflag = (OPOST | ONLCR);
1694
1695   /* control modes */
1696   tio->c_cflag = (CS8 | CREAD);
1697
1698   /* line discipline modes */
1699   tio->c_lflag = (ISIG | ICANON | IEXTEN | ECHO
1700 # if defined (ECHOCTL) && defined (ECHOKE)
1701                   | ECHOCTL | ECHOKE
1702 # endif
1703                   | ECHOE | ECHOK);
1704 # else                          /* HAVE_TERMIOS_H */
1705
1706   /*
1707   * sgtty interface
1708   */
1709
1710   /* get parameters -- gtty */
1711   if (ioctl(STDIN_FILENO, TIOCGETP, &(tio->sg)) < 0)
1712     {
1713       tio->sg.sg_erase = CERASE;      /* ^H */
1714       tio->sg.sg_kill = CKILL;        /* ^U */
1715     }
1716   if (erase != -1)
1717     tio->sg.sg_erase = (char)erase;
1718
1719   tio->sg.sg_flags = (CRMOD | ECHO | EVENP | ODDP);
1720
1721   /* get special characters */
1722   if (ioctl(STDIN_FILENO, TIOCGETC, &(tio->tc)) < 0)
1723     {
1724       tio->tc.t_intrc = CINTR;        /* ^C */
1725       tio->tc.t_quitc = CQUIT;        /* ^\ */
1726       tio->tc.t_startc = CSTART;      /* ^Q */
1727       tio->tc.t_stopc = CSTOP;        /* ^S */
1728       tio->tc.t_eofc = CEOF;  /* ^D */
1729       tio->tc.t_brkc = -1;
1730     }
1731   /* get local special chars */
1732   if (ioctl(STDIN_FILENO, TIOCGLTC, &(tio->lc)) < 0)
1733     {
1734       tio->lc.t_suspc = CSUSP;        /* ^Z */
1735       tio->lc.t_dsuspc = CDSUSP;      /* ^Y */
1736       tio->lc.t_rprntc = CRPRNT;      /* ^R */
1737       tio->lc.t_flushc = CFLUSH;      /* ^O */
1738       tio->lc.t_werasc = CWERASE;     /* ^W */
1739       tio->lc.t_lnextc = CLNEXT;      /* ^V */
1740     }
1741   /* get line discipline */
1742   ioctl(STDIN_FILENO, TIOCGETD, &(tio->line));
1743 # ifdef NTTYDISC
1744
1745   tio->line = NTTYDISC;
1746 # endif                         /* NTTYDISC */
1747
1748   tio->local = (LCRTBS | LCRTERA | LCTLECH | LPASS8 | LCRTKIL);
1749 #endif                          /* HAVE_TERMIOS_H */
1750
1751   /*
1752    * Debugging
1753    */
1754 #ifdef DEBUG_TTYMODE
1755 #ifdef HAVE_TERMIOS_H
1756   /* c_iflag bits */
1757   fprintf(stderr, "Input flags\n");
1758
1759   /* cpp token stringize doesn't work on all machines <sigh> */
1760 # define FOO(flag,name)                 \
1761     if ((tio->c_iflag) & flag)          \
1762         fprintf (stderr, "%s ", name)
1763
1764   /* c_iflag bits */
1765   FOO(IGNBRK, "IGNBRK");
1766   FOO(BRKINT, "BRKINT");
1767   FOO(IGNPAR, "IGNPAR");
1768   FOO(PARMRK, "PARMRK");
1769   FOO(INPCK, "INPCK");
1770   FOO(ISTRIP, "ISTRIP");
1771   FOO(INLCR, "INLCR");
1772   FOO(IGNCR, "IGNCR");
1773   FOO(ICRNL, "ICRNL");
1774   FOO(IXON, "IXON");
1775   FOO(IXOFF, "IXOFF");
1776 # ifdef IUCLC
1777
1778   FOO(IUCLC, "IUCLC");
1779 # endif
1780 # ifdef IXANY
1781
1782   FOO(IXANY, "IXANY");
1783 # endif
1784 # ifdef IMAXBEL
1785
1786   FOO(IMAXBEL, "IMAXBEL");
1787 # endif
1788
1789   fprintf(stderr, "\n");
1790
1791 # undef FOO
1792 # define FOO(entry, name)                                       \
1793     fprintf(stderr, "%-8s = %#04o\n", name, tio->c_cc [entry])
1794
1795   FOO(VINTR, "VINTR");
1796   FOO(VQUIT, "VQUIT");
1797   FOO(VERASE, "VERASE");
1798   FOO(VKILL, "VKILL");
1799   FOO(VEOF, "VEOF");
1800   FOO(VEOL, "VEOL");
1801 # ifdef VEOL2
1802
1803   FOO(VEOL2, "VEOL2");
1804 # endif
1805 # ifdef VSWTC
1806
1807   FOO(VSWTC, "VSWTC");
1808 # endif
1809 # ifdef VSWTCH
1810
1811   FOO(VSWTCH, "VSWTCH");
1812 # endif
1813
1814   FOO(VSTART, "VSTART");
1815   FOO(VSTOP, "VSTOP");
1816   FOO(VSUSP, "VSUSP");
1817 # ifdef VDSUSP
1818
1819   FOO(VDSUSP, "VDSUSP");
1820 # endif
1821 # ifdef VREPRINT
1822
1823   FOO(VREPRINT, "VREPRINT");
1824 # endif
1825 # ifdef VDISCRD
1826
1827   FOO(VDISCRD, "VDISCRD");
1828 # endif
1829 # ifdef VWERSE
1830
1831   FOO(VWERSE, "VWERSE");
1832 # endif
1833 # ifdef VLNEXT
1834
1835   FOO(VLNEXT, "VLNEXT");
1836 # endif
1837
1838   fprintf(stderr, "\n");
1839 # undef FOO
1840 # endif                         /* HAVE_TERMIOS_H */
1841 #endif                          /* DEBUG_TTYMODE */
1842 }
1843
1844 /*----------------------- end-of-file (C source) -----------------------*/