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