1 /*--------------------------------*-C-*---------------------------------*
2 * File: init.c
3 *----------------------------------------------------------------------*
4 *
5 * All portions of code are copyright by their respective author/s.
6 * Copyright (c) 1992 John Bovey <jdb@ukc.ac.uk>
7 * Copyright (c) 1994 Robert Nation <nation@rocket.sanders.lockheed.com>
8 * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
9 * Copyright (c) 1999 D J Hawkey Jr <hawkeyd@visi.com>
10 * Copyright (c) 2003 marcus at #fluxbox on freenode.net
11 * Copyright (c) 2004 Mr. Dobalina <losermcloser@users.sourceforge.net>
12 * Copyright (c) 2003-2004 Marc Lehmann <pcg@goof.com>
13 * Copyright (c) 2004-2006 Jingmin Zhou <jimmyzhou@users.sourceforge.net>
14 * Copyright (c) 2005-2006 Gautam Iyer <gi1242@users.sourceforge.net>
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 #include "../config.h"
32 #include "rxvt.h"
33
34 #ifdef XFT_SUPPORT
35 # include "xftacs.h"
36 #endif
37
38
39 /* #define XTERM_REVERSE_VIDEO 1 */
40
41
42 /*--------------------------------------------------------------------*
43 * BEGIN `INTERNAL' ROUTINE PROTOTYPES *
44 *--------------------------------------------------------------------*/
45 #if defined(OS_SVR4) && !defined(_POSIX_VERSION)
46 int rxvt_getdtablesize ();
47 #endif
48 int rxvt_xerror_handler (const Display*, const XErrorEvent*);
49 void rxvt_init_colors (rxvt_t*);
50 void rxvt_init_win_size (rxvt_t*);
51 void rxvt_color_aliases (rxvt_t*, int);
52 void rxvt_get_ourmods (rxvt_t*);
53 int rxvt_run_child (rxvt_t*, int, const char**);
54 void rxvt_get_ttymode (ttymode_t*, int);
55 /*--------------------------------------------------------------------*
56 * END `INTERNAL' ROUTINE PROTOTYPES *
57 *--------------------------------------------------------------------*/
58
59
60
61 const char *const def_colorName[] = {
62 COLOR_FOREGROUND,
63 COLOR_BACKGROUND,
64 /* low-intensity colors */
65 "black", /* 0: black (#000000) */
66 #ifndef NO_BRIGHTCOLOR
67 "red3", /* 1: red (#CD0000) */
68 "green3", /* 2: green (#00CD00) */
69 "yellow3", /* 3: yellow (#CDCD00) */
70 "blue3", /* 4: blue (#0000CD) */
71 "magenta3", /* 5: magenta (#CD00CD) */
72 "cyan3", /* 6: cyan (#00CDCD) */
73 # ifdef XTERM_COLORS
74 "grey90", /* 7: white (#E5E5E5) */
75 # else
76 "antiquewhite", /* 7: white (#FAEBD7) */
77 # endif
78 /* high-intensity colors */
79 # ifdef XTERM_COLORS
80 "grey30", /* 8: bright black (#4D4D4D) */
81 # else
82 "grey25", /* 8: bright black (#404040) */
83 # endif
84 #endif /* NO_BRIGHTCOLOR */
85 "red", /* 1/9: bright red (#FF0000) */
86 "green", /* 2/10: bright green (#00FF00) */
87 "yellow", /* 3/11: bright yellow (#FFFF00) */
88 "blue", /* 4/12: bright blue (#0000FF) */
89 "magenta", /* 5/13: bright magenta (#FF00FF) */
90 "cyan", /* 6/14: bright cyan (#00FFFF) */
91 "white", /* 7/15: bright white (#FFFFFF) */
92 #ifdef TTY_256COLOR
93 # ifdef XTERM_COLORS
94 /* use the same color cube as xterm. 16-231 is a more or less uniform
95 * rgb ramp, and 231-255 is a greyscale ramp */
96 "rgb:00/00/00", /* default 16-255 color table */
97 "rgb:00/00/5f", /* consists of 6x6x6 colour cub */
98 "rgb:00/00/87", /* and a 24 greyscale ramp w/o */
99 "rgb:00/00/af", /* black or white */
100 "rgb:00/00/d7",
101 "rgb:00/00/ff",
102 "rgb:00/5f/00",
103 "rgb:00/5f/5f",
104 "rgb:00/5f/87",
105 "rgb:00/5f/af",
106 "rgb:00/5f/d7",
107 "rgb:00/5f/ff",
108 "rgb:00/87/00",
109 "rgb:00/87/5f",
110 "rgb:00/87/87",
111 "rgb:00/87/af",
112 "rgb:00/87/d7",
113 "rgb:00/87/ff",
114 "rgb:00/af/00",
115 "rgb:00/af/5f",
116 "rgb:00/af/87",
117 "rgb:00/af/af",
118 "rgb:00/af/d7",
119 "rgb:00/af/ff",
120 "rgb:00/d7/00",
121 "rgb:00/d7/5f",
122 "rgb:00/d7/87",
123 "rgb:00/d7/af",
124 "rgb:00/d7/d7",
125 "rgb:00/d7/ff",
126 "rgb:00/ff/00",
127 "rgb:00/ff/5f",
128 "rgb:00/ff/87",
129 "rgb:00/ff/af",
130 "rgb:00/ff/d7",
131 "rgb:00/ff/ff",
132 "rgb:5f/00/00",
133 "rgb:5f/00/5f",
134 "rgb:5f/00/87",
135 "rgb:5f/00/af",
136 "rgb:5f/00/d7",
137 "rgb:5f/00/ff",
138 "rgb:5f/5f/00",
139 "rgb:5f/5f/5f",
140 "rgb:5f/5f/87",
141 "rgb:5f/5f/af",
142 "rgb:5f/5f/d7",
143 "rgb:5f/5f/ff",
144 "rgb:5f/87/00",
145 "rgb:5f/87/5f",
146 "rgb:5f/87/87",
147 "rgb:5f/87/af",
148 "rgb:5f/87/d7",
149 "rgb:5f/87/ff",
150 "rgb:5f/af/00",
151 "rgb:5f/af/5f",
152 "rgb:5f/af/87",
153 "rgb:5f/af/af",
154 "rgb:5f/af/d7",
155 "rgb:5f/af/ff",
156 "rgb:5f/d7/00",
157 "rgb:5f/d7/5f",
158 "rgb:5f/d7/87",
159 "rgb:5f/d7/af",
160 "rgb:5f/d7/d7",
161 "rgb:5f/d7/ff",
162 "rgb:5f/ff/00",
163 "rgb:5f/ff/5f",
164 "rgb:5f/ff/87",
165 "rgb:5f/ff/af",
166 "rgb:5f/ff/d7",
167 "rgb:5f/ff/ff",
168 "rgb:87/00/00",
169 "rgb:87/00/5f",
170 "rgb:87/00/87",
171 "rgb:87/00/af",
172 "rgb:87/00/d7",
173 "rgb:87/00/ff",
174 "rgb:87/5f/00",
175 "rgb:87/5f/5f",
176 "rgb:87/5f/87",
177 "rgb:87/5f/af",
178 "rgb:87/5f/d7",
179 "rgb:87/5f/ff",
180 "rgb:87/87/00",
181 "rgb:87/87/5f",
182 "rgb:87/87/87",
183 "rgb:87/87/af",
184 "rgb:87/87/d7",
185 "rgb:87/87/ff",
186 "rgb:87/af/00",
187 "rgb:87/af/5f",
188 "rgb:87/af/87",
189 "rgb:87/af/af",
190 "rgb:87/af/d7",
191 "rgb:87/af/ff",
192 "rgb:87/d7/00",
193 "rgb:87/d7/5f",
194 "rgb:87/d7/87",
195 "rgb:87/d7/af",
196 "rgb:87/d7/d7",
197 "rgb:87/d7/ff",
198 "rgb:87/ff/00",
199 "rgb:87/ff/5f",
200 "rgb:87/ff/87",
201 "rgb:87/ff/af",
202 "rgb:87/ff/d7",
203 "rgb:87/ff/ff",
204 "rgb:af/00/00",
205 "rgb:af/00/5f",
206 "rgb:af/00/87",
207 "rgb:af/00/af",
208 "rgb:af/00/d7",
209 "rgb:af/00/ff",
210 "rgb:af/5f/00",
211 "rgb:af/5f/5f",
212 "rgb:af/5f/87",
213 "rgb:af/5f/af",
214 "rgb:af/5f/d7",
215 "rgb:af/5f/ff",
216 "rgb:af/87/00",
217 "rgb:af/87/5f",
218 "rgb:af/87/87",
219 "rgb:af/87/af",
220 "rgb:af/87/d7",
221 "rgb:af/87/ff",
222 "rgb:af/af/00",
223 "rgb:af/af/5f",
224 "rgb:af/af/87",
225 "rgb:af/af/af",
226 "rgb:af/af/d7",
227 "rgb:af/af/ff",
228 "rgb:af/d7/00",
229 "rgb:af/d7/5f",
230 "rgb:af/d7/87",
231 "rgb:af/d7/af",
232 "rgb:af/d7/d7",
233 "rgb:af/d7/ff",
234 "rgb:af/ff/00",
235 "rgb:af/ff/5f",
236 "rgb:af/ff/87",
237 "rgb:af/ff/af",
238 "rgb:af/ff/d7",
239 "rgb:af/ff/ff",
240 "rgb:d7/00/00",
241 "rgb:d7/00/5f",
242 "rgb:d7/00/87",
243 "rgb:d7/00/af",
244 "rgb:d7/00/d7",
245 "rgb:d7/00/ff",
246 "rgb:d7/5f/00",
247 "rgb:d7/5f/5f",
248 "rgb:d7/5f/87",
249 "rgb:d7/5f/af",
250 "rgb:d7/5f/d7",
251 "rgb:d7/5f/ff",
252 "rgb:d7/87/00",
253 "rgb:d7/87/5f",
254 "rgb:d7/87/87",
255 "rgb:d7/87/af",
256 "rgb:d7/87/d7",
257 "rgb:d7/87/ff",
258 "rgb:d7/af/00",
259 "rgb:d7/af/5f",
260 "rgb:d7/af/87",
261 "rgb:d7/af/af",
262 "rgb:d7/af/d7",
263 "rgb:d7/af/ff",
264 "rgb:d7/d7/00",
265 "rgb:d7/d7/5f",
266 "rgb:d7/d7/87",
267 "rgb:d7/d7/af",
268 "rgb:d7/d7/d7",
269 "rgb:d7/d7/ff",
270 "rgb:d7/ff/00",
271 "rgb:d7/ff/5f",
272 "rgb:d7/ff/87",
273 "rgb:d7/ff/af",
274 "rgb:d7/ff/d7",
275 "rgb:d7/ff/ff",
276 "rgb:ff/00/00",
277 "rgb:ff/00/5f",
278 "rgb:ff/00/87",
279 "rgb:ff/00/af",
280 "rgb:ff/00/d7",
281 "rgb:ff/00/ff",
282 "rgb:ff/5f/00",
283 "rgb:ff/5f/5f",
284 "rgb:ff/5f/87",
285 "rgb:ff/5f/af",
286 "rgb:ff/5f/d7",
287 "rgb:ff/5f/ff",
288 "rgb:ff/87/00",
289 "rgb:ff/87/5f",
290 "rgb:ff/87/87",
291 "rgb:ff/87/af",
292 "rgb:ff/87/d7",
293 "rgb:ff/87/ff",
294 "rgb:ff/af/00",
295 "rgb:ff/af/5f",
296 "rgb:ff/af/87",
297 "rgb:ff/af/af",
298 "rgb:ff/af/d7",
299 "rgb:ff/af/ff",
300 "rgb:ff/d7/00",
301 "rgb:ff/d7/5f",
302 "rgb:ff/d7/87",
303 "rgb:ff/d7/af",
304 "rgb:ff/d7/d7",
305 "rgb:ff/d7/ff",
306 "rgb:ff/ff/00",
307 "rgb:ff/ff/5f",
308 "rgb:ff/ff/87",
309 "rgb:ff/ff/af",
310 "rgb:ff/ff/d7",
311 "rgb:ff/ff/ff",
312 # else /* !XTERM_COLORS */
313 "rgbi:0/0/0", /* default 16-255 color table */
314 "rgbi:0/0/.2", /* consists of 6x6x6 colour cubes */
315 "rgbi:0/0/.4", /* and a 24 greyscale ramp w/o */
316 "rgbi:0/0/.6", /* black or white */
317 "rgbi:0/0/.8",
318 "rgbi:0/0/1",
319 "rgbi:0/.2/0",
320 "rgbi:0/.2/.2",
321 "rgbi:0/.2/.4",
322 "rgbi:0/.2/.6",
323 "rgbi:0/.2/.8",
324 "rgbi:0/.2/1",
325 "rgbi:0/.4/0",
326 "rgbi:0/.4/.2",
327 "rgbi:0/.4/.4",
328 "rgbi:0/.4/.6",
329 "rgbi:0/.4/.8",
330 "rgbi:0/.4/1",
331 "rgbi:0/.6/0",
332 "rgbi:0/.6/.2",
333 "rgbi:0/.6/.4",
334 "rgbi:0/.6/.6",
335 "rgbi:0/.6/.8",
336 "rgbi:0/.6/1",
337 "rgbi:0/.8/0",
338 "rgbi:0/.8/.2",
339 "rgbi:0/.8/.4",
340 "rgbi:0/.8/.6",
341 "rgbi:0/.8/.8",
342 "rgbi:0/.8/1",
343 "rgbi:0/1/0",
344 "rgbi:0/1/.2",
345 "rgbi:0/1/.4",
346 "rgbi:0/1/.6",
347 "rgbi:0/1/.8",
348 "rgbi:0/1/1",
349 "rgbi:.2/0/0",
350 "rgbi:.2/0/.2",
351 "rgbi:.2/0/.4",
352 "rgbi:.2/0/.6",
353 "rgbi:.2/0/.8",
354 "rgbi:.2/0/1",
355 "rgbi:.2/.2/0",
356 "rgbi:.2/.2/.2",
357 "rgbi:.2/.2/.4",
358 "rgbi:.2/.2/.6",
359 "rgbi:.2/.2/.8",
360 "rgbi:.2/.2/1",
361 "rgbi:.2/.4/0",
362 "rgbi:.2/.4/.2",
363 "rgbi:.2/.4/.4",
364 "rgbi:.2/.4/.6",
365 "rgbi:.2/.4/.8",
366 "rgbi:.2/.4/1",
367 "rgbi:.2/.6/0",
368 "rgbi:.2/.6/.2",
369 "rgbi:.2/.6/.4",
370 "rgbi:.2/.6/.6",
371 "rgbi:.2/.6/.8",
372 "rgbi:.2/.6/1",
373 "rgbi:.2/.8/0",
374 "rgbi:.2/.8/.2",
375 "rgbi:.2/.8/.4",
376 "rgbi:.2/.8/.6",
377 "rgbi:.2/.8/.8",
378 "rgbi:.2/.8/1",
379 "rgbi:.2/1/0",
380 "rgbi:.2/1/.2",
381 "rgbi:.2/1/.4",
382 "rgbi:.2/1/.6",
383 "rgbi:.2/1/.8",
384 "rgbi:.2/1/1",
385 "rgbi:.4/0/0",
386 "rgbi:.4/0/.2",
387 "rgbi:.4/0/.4",
388 "rgbi:.4/0/.6",
389 "rgbi:.4/0/.8",
390 "rgbi:.4/0/1",
391 "rgbi:.4/.2/0",
392 "rgbi:.4/.2/.2",
393 "rgbi:.4/.2/.4",
394 "rgbi:.4/.2/.6",
395 "rgbi:.4/.2/.8",
396 "rgbi:.4/.2/1",
397 "rgbi:.4/.4/0",
398 "rgbi:.4/.4/.2",
399 "rgbi:.4/.4/.4",
400 "rgbi:.4/.4/.6",
401 "rgbi:.4/.4/.8",
402 "rgbi:.4/.4/1",
403 "rgbi:.4/.6/0",
404 "rgbi:.4/.6/.2",
405 "rgbi:.4/.6/.4",
406 "rgbi:.4/.6/.6",
407 "rgbi:.4/.6/.8",
408 "rgbi:.4/.6/1",
409 "rgbi:.4/.8/0",
410 "rgbi:.4/.8/.2",
411 "rgbi:.4/.8/.4",
412 "rgbi:.4/.8/.6",
413 "rgbi:.4/.8/.8",
414 "rgbi:.4/.8/1",
415 "rgbi:.4/1/0",
416 "rgbi:.4/1/.2",
417 "rgbi:.4/1/.4",
418 "rgbi:.4/1/.6",
419 "rgbi:.4/1/.8",
420 "rgbi:.4/1/1",
421 "rgbi:.6/0/0",
422 "rgbi:.6/0/.2",
423 "rgbi:.6/0/.4",
424 "rgbi:.6/0/.6",
425 "rgbi:.6/0/.8",
426 "rgbi:.6/0/1",
427 "rgbi:.6/.2/0",
428 "rgbi:.6/.2/.2",
429 "rgbi:.6/.2/.4",
430 "rgbi:.6/.2/.6",
431 "rgbi:.6/.2/.8",
432 "rgbi:.6/.2/1",
433 "rgbi:.6/.4/0",
434 "rgbi:.6/.4/.2",
435 "rgbi:.6/.4/.4",
436 "rgbi:.6/.4/.6",
437 "rgbi:.6/.4/.8",
438 "rgbi:.6/.4/1",
439 "rgbi:.6/.6/0",
440 "rgbi:.6/.6/.2",
441 "rgbi:.6/.6/.4",
442 "rgbi:.6/.6/.6",
443 "rgbi:.6/.6/.8",
444 "rgbi:.6/.6/1",
445 "rgbi:.6/.8/0",
446 "rgbi:.6/.8/.2",
447 "rgbi:.6/.8/.4",
448 "rgbi:.6/.8/.6",
449 "rgbi:.6/.8/.8",
450 "rgbi:.6/.8/1",
451 "rgbi:.6/1/0",
452 "rgbi:.6/1/.2",
453 "rgbi:.6/1/.4",
454 "rgbi:.6/1/.6",
455 "rgbi:.6/1/.8",
456 "rgbi:.6/1/1",
457 "rgbi:.8/0/0",
458 "rgbi:.8/0/.2",
459 "rgbi:.8/0/.4",
460 "rgbi:.8/0/.6",
461 "rgbi:.8/0/.8",
462 "rgbi:.8/0/1",
463 "rgbi:.8/.2/0",
464 "rgbi:.8/.2/.2",
465 "rgbi:.8/.2/.4",
466 "rgbi:.8/.2/.6",
467 "rgbi:.8/.2/.8",
468 "rgbi:.8/.2/1",
469 "rgbi:.8/.4/0",
470 "rgbi:.8/.4/.2",
471 "rgbi:.8/.4/.4",
472 "rgbi:.8/.4/.6",
473 "rgbi:.8/.4/.8",
474 "rgbi:.8/.4/1",
475 "rgbi:.8/.6/0",
476 "rgbi:.8/.6/.2",
477 "rgbi:.8/.6/.4",
478 "rgbi:.8/.6/.6",
479 "rgbi:.8/.6/.8",
480 "rgbi:.8/.6/1",
481 "rgbi:.8/.8/0",
482 "rgbi:.8/.8/.2",
483 "rgbi:.8/.8/.4",
484 "rgbi:.8/.8/.6",
485 "rgbi:.8/.8/.8",
486 "rgbi:.8/.8/1",
487 "rgbi:.8/1/0",
488 "rgbi:.8/1/.2",
489 "rgbi:.8/1/.4",
490 "rgbi:.8/1/.6",
491 "rgbi:.8/1/.8",
492 "rgbi:.8/1/1",
493 "rgbi:1/0/0",
494 "rgbi:1/0/.2",
495 "rgbi:1/0/.4",
496 "rgbi:1/0/.6",
497 "rgbi:1/0/.8",
498 "rgbi:1/0/1",
499 "rgbi:1/.2/0",
500 "rgbi:1/.2/.2",
501 "rgbi:1/.2/.4",
502 "rgbi:1/.2/.6",
503 "rgbi:1/.2/.8",
504 "rgbi:1/.2/1",
505 "rgbi:1/.4/0",
506 "rgbi:1/.4/.2",
507 "rgbi:1/.4/.4",
508 "rgbi:1/.4/.6",
509 "rgbi:1/.4/.8",
510 "rgbi:1/.4/1",
511 "rgbi:1/.6/0",
512 "rgbi:1/.6/.2",
513 "rgbi:1/.6/.4",
514 "rgbi:1/.6/.6",
515 "rgbi:1/.6/.8",
516 "rgbi:1/.6/1",
517 "rgbi:1/.8/0",
518 "rgbi:1/.8/.2",
519 "rgbi:1/.8/.4",
520 "rgbi:1/.8/.6",
521 "rgbi:1/.8/.8",
522 "rgbi:1/.8/1",
523 "rgbi:1/1/0",
524 "rgbi:1/1/.2",
525 "rgbi:1/1/.4",
526 "rgbi:1/1/.6",
527 "rgbi:1/1/.8",
528 "rgbi:1/1/1",
529 # endif /* XTERM_COLORS */
530 "rgb:08/08/08", /* xterm, rxvt, mrxvt use the same greyscale ramp */
531 "rgb:12/12/12",
532 "rgb:1c/1c/1c",
533 "rgb:26/26/26",
534 "rgb:30/30/30",
535 "rgb:3a/3a/3a",
536 "rgb:44/44/44",
537 "rgb:4e/4e/4e",
538 "rgb:58/58/58",
539 "rgb:62/62/62",
540 "rgb:6c/6c/6c",
541 "rgb:76/76/76",
542 "rgb:80/80/80",
543 "rgb:8a/8a/8a",
544 "rgb:94/94/94",
545 "rgb:9e/9e/9e",
546 "rgb:a8/a8/a8",
547 "rgb:b2/b2/b2",
548 "rgb:bc/bc/bc",
549 "rgb:c6/c6/c6",
550 "rgb:d0/d0/d0",
551 "rgb:da/da/da",
552 "rgb:e4/e4/e4",
553 "rgb:ee/ee/ee",
554 #endif /* TTY_256COLOR */
555 #ifndef NO_CURSORCOLOR
556 COLOR_CURSOR_BACKGROUND,
557 COLOR_CURSOR_FOREGROUND,
558 #endif /* ! NO_CURSORCOLOR */
559 NULL, /* Color_pointer */
560 NULL, /* Color_border */
561 NULL, /* Color_ufbg */
562 #ifndef NO_BOLD_UNDERLINE_REVERSE
563 NULL, /* Color_BD */
564 NULL, /* Color_UL */
565 NULL, /* Color_RV */
566 #endif /* ! NO_BOLD_UNDERLINE_REVERSE */
567 #ifdef OPTION_HC
568 NULL, /* Color_HL */
569 #endif
570 #ifdef KEEP_SCROLLCOLOR
571 COLOR_SCROLLBAR,
572 COLOR_SCROLLTROUGH,
573 #endif /* KEEP_SCROLLCOLOR */
574 #ifdef TINTING_SUPPORT
575 # ifdef HAVE_LIBXRENDER
576 "rgb:00/00/00",
577 # else
578 "rgb:ff/ff/ff",
579 # endif
580 #endif
581 };
582
583
584 /*
585 ** MUST sync with rxvt.h:enum XA_XXXX
586 */
587 const char *const xa_names[NUM_XA] = {
588 "COMPOUND_TEXT",
589 "UTF8_STRING",
590 "TEXT",
591 "MULTIPLE",
592 "TARGETS",
593 "TIMESTAMP",
594 "VT_SELECTION",
595 "INCR",
596 "WM_DELETE_WINDOW",
597 "_NET_WM_DESKTOP",
598 "_WIN_WORKSPACE",
599 "_NET_WM_NAME",
600 "_NET_WM_ICON_NAME",
601 "WM_CLIENT_LEADER",
602 "_NET_WM_WINDOW_OPACITY",
603 #ifndef NO_FRILLS
604 "_NET_WM_PID",
605 #endif
606 #ifdef HAVE_X11_SM_SMLIB_H
607 "SM_CLIENT_ID",
608 #endif
609 #ifdef USE_XIM
610 "WM_LOCALE_NAME",
611 #endif
612 #ifdef TRANSPARENT
613 "_XROOTPMAP_ID",
614 "_XSETROOT_ID",
615 #endif
616 #ifdef OFFIX_DND
617 "DndProtocol",
618 "DndSelection",
619 #endif
620 "CLIPBOARD"
621 };
622
623 /* substitute system functions */
624 #if defined(OS_SVR4) && ! defined(_POSIX_VERSION)
625 /* INTPROTO */
626 int
rxvt_getdtablesize(void)627 rxvt_getdtablesize(void)
628 {
629 struct rlimit rlim;
630
631 getrlimit(RLIMIT_NOFILE, &rlim);
632 return rlim.rlim_cur;
633 }
634 #endif
635
636
637 /* EXTPROTO */
638 int
rxvt_init_vars(rxvt_t * r)639 rxvt_init_vars(rxvt_t *r)
640 {
641 register int i;
642 struct rxvt_hidden* h;
643
644
645 MEMSET(r, 0, sizeof(rxvt_t));
646
647 h = r->h = (struct rxvt_hidden *)rxvt_calloc(1, sizeof(struct rxvt_hidden));
648
649 for (i = 0; i < MAX_PAGES; i ++)
650 {
651 /* Initialize vts_idx for each term_t structure */
652 r->vterm[i].vts_idx = -1;
653 /* Initialize each vts pointer */
654 SET_NULL(r->vts[i]);
655 }
656
657 SET_NULL(r->Xdisplay);
658 #ifdef USE_XIM
659 SET_NULL(r->TermWin.fontset);
660 #endif
661 SET_NULL(r->TermWin.font);
662 #ifdef MULTICHAR_SET
663 SET_NULL(r->TermWin.mfont);
664 #endif
665 #ifndef NO_BOLDFONT
666 SET_NULL(r->TermWin.bfont);
667 #endif
668
669 #ifdef XFT_SUPPORT
670 SET_NULL(r->TermWin.xftpattern);
671 SET_NULL(r->TermWin.xftfont);
672 SET_NULL(r->TermWin.xftpfont);
673 SET_NULL(r->TermWin.xftPfont);
674 # ifndef NO_BOLDFONT
675 SET_NULL(r->TermWin.xftbfont);
676 # endif /* NO_BOLDFONT */
677 # ifdef MULTICHAR_SET
678 # ifdef HAVE_ICONV_H
679 r->TermWin.xfticonv = (iconv_t) -1;
680 # endif
681 SET_NULL(r->TermWin.xftmpattern);
682 SET_NULL(r->TermWin.xftmfont);
683 # endif /* MULTICHAR_SET */
684 #endif /* XFT_SUPPORT */
685
686 UNSET_ATOM(h->xa[XA_COMPOUND_TEXT]);
687 UNSET_ATOM(h->xa[XA_MULTIPLE]);
688 UNSET_ATOM(h->xa[XA_TARGETS]);
689 UNSET_ATOM(h->xa[XA_TEXT]);
690 UNSET_ATOM(h->xa[XA_TIMESTAMP]);
691 UNSET_ATOM(h->xa[XA_VT_SELECTION]);
692 UNSET_ATOM(h->xa[XA_INCR]);
693 h->locale = NULL;
694
695 # ifdef HAVE_MENUBAR
696 SET_NULL(h->BuildMenu);
697 SET_NULL(h->ActiveMenu);
698 SET_NULL(h->popupMenu[0]);
699 SET_NULL(h->popupMenu[1]);
700 SET_NULL(h->popupMenu[2]);
701 h->showingMenu = 0;
702
703 /* Set the current menubar to empty defaults */
704 SET_NULL(h->MenuBar.head);
705 SET_NULL(h->MenuBar.tail);
706 SET_NULL(h->MenuBar.title);
707 # endif
708
709 # ifdef USE_XIM
710 SET_NULL(h->Input_Context);
711 # endif
712 /* SET_NULL(h->v_bufstr); */
713 SET_NULL(h->buffer);
714
715 # ifdef TRANSPARENT
716 h->am_pixmap_trans = 0;
717 h->am_transparent = 0;
718 UNSET_PIXMAP(h->rootPixmap);
719 h->bgRefreshInterval = DEFAULT_BG_REFRESH_INTERVAL;
720 h->lastCNotify.tv_sec = 0; /* No BG update pending */
721 # endif
722
723 /* Initialize timeouts to 0 */
724 for( i=NUM_TIMEOUTS; i--;)
725 h->timeout[i].tv_sec = 0;
726
727
728 /* Back to undocumented code :) */
729 h->MEvent.time = CurrentTime;
730 h->MEvent.button = AnyButton;
731 r->Options[0] = DEFAULT_OPTIONS;
732 r->Options[1] = DEFAULT_OPTIONS2;
733 r->Options[2] = DEFAULT_OPTIONS3;
734 r->Options[3] = DEFAULT_OPTIONS4;
735 h->want_clip_refresh = 0;
736 /*
737 * We only want to set want_resize when we call XResizeWindow. In that
738 * case if XResizeWindow fails, we know that we called it, and can run
739 * our internal resize routines anyway (e.g. put the tabbar in place)
740 */
741 h->want_resize = 0;
742 h->ttygid = -1;
743 r->Xfd = -1;
744 #ifdef USE_FIFO
745 r->fifo_fd = -1;
746 #endif
747 r->ndead_childs = 0;
748
749 r->nAsyncChilds = 0;
750
751 /* default values */
752 #ifdef NO_FRILLS
753 r->TermWin.int_bwidth = DEFAULT_INTERNALBORDERWIDTH;
754 r->TermWin.ext_bwidth = DEFAULT_EXTERNALBORDERWIDTH;
755 #else
756 r->TermWin.int_bwidth = (INTERNALBORDERWIDTH >= 0 && INTERNALBORDERWIDTH <= MAX_INTERNALBORDERWIDTH) ? INTERNALBORDERWIDTH : DEFAULT_INTERNALBORDERWIDTH;
757 r->TermWin.ext_bwidth = (EXTERNALBORDERWIDTH >= 0 && EXTERNALBORDERWIDTH <= MAX_EXTERNALBORDERWIDTH) ? EXTERNALBORDERWIDTH : DEFAULT_EXTERNALBORDERWIDTH;
758 #endif
759
760 #ifndef NO_LINESPACE
761 r->TermWin.lineSpace = (LINESPACE >= 0 && LINESPACE <= MAX_LINESPACE) ? LINESPACE : DEFAULT_LINESPACE;
762 #endif
763
764 #ifdef CURSOR_BLINK
765 r->h->blinkInterval = DEFAULT_BLINK_TIME;
766 #endif
767 #ifdef POINTER_BLANK
768 r->h->pointerBlankDelay = DEFAULT_BLANKDELAY;
769 #endif
770
771 /* Initialize selection data */
772 #ifndef NO_NEW_SELECTION
773 r->selection_style = NEW_SELECT;
774 #else
775 r->selection_style = OLD_SELECT;
776 #endif
777 r->selection.vt = -1;
778 r->selection.op = SELECTION_CLEAR;
779 r->selection.screen = PRIMARY;
780 r->selection.clicks = 0;
781 SET_NULL(r->selection.text);
782 r->selection.len = 0;
783 r->selection.beg.row = 0;
784 r->selection.beg.col = 0;
785 r->selection.end.row = 0;
786 r->selection.end.col = 0;
787
788 #ifndef NO_BRIGHTCOLOR
789 h->colorfgbg = DEFAULT_RSTYLE;
790 #endif
791 #ifdef GREEK_SUPPORT
792 h->ks_greekmodeswith = GREEK_KEYBOARD_MODESWITCH;
793 #endif
794 h->refresh_type = SLOW_REFRESH;
795 UNSET_REGION(h->refreshRegion); /* Will be created when needed */
796 h->prev_nrow = h->prev_ncol = 0;
797
798 r->encoding_method = ENC_NOENC;
799 h->multichar_decode = rxvt_decode_dummy;
800
801 h->oldcursor.row = h->oldcursor.col = -1;
802 h->last_bot = h->last_state = -1;
803
804 #ifdef HAVE_X11_SM_SMLIB_H
805 SET_NULL(r->TermWin.sm_conn);
806 SET_NULL(r->TermWin.ice_conn);
807 r->TermWin.ice_fd = -1;
808 SET_NULL(r->TermWin.sm_client_id);
809 #endif
810
811 #ifdef USE_FIFO
812 {
813 char fifo_name[FILENAME_MAX];
814
815 sprintf( fifo_name, "/tmp/.mrxvt-%d", getpid() );
816 r->fbuf_ptr = r->fifo_buf;
817 r->fifo_name = STRDUP( fifo_name );
818 }
819 #endif/*USE_FIFO*/
820
821 r->tabClicked = -1; /* No tab has been clicked by user */
822
823 h->allowedxerror = 0;
824 h->xerror_return = Success;
825 return 0;
826 }
827
828
829 /* EXTPROTO */
830 void
rxvt_init_secondary(rxvt_t * r)831 rxvt_init_secondary(rxvt_t *r)
832 {
833 int i, num_fds;
834 #ifdef TTY_GID_SUPPORT
835 struct group *gr = getgrnam("tty");
836
837 if (gr) /* change group ownership of tty to "tty" */
838 {
839 r->h->ttygid = gr->gr_gid;
840 }
841 else
842 #endif /* TTY_GID_SUPPORT */
843 {
844 r->h->ttygid = getgid();
845 }
846
847 rxvt_set_default_locale (r);
848
849 /* get number of available file descriptors */
850 #if defined(_POSIX_VERSION) || ! defined(OS_SVR4)
851 num_fds = (int)sysconf(_SC_OPEN_MAX);
852 #else
853 num_fds = rxvt_getdtablesize();
854 #endif
855
856 /*
857 ** Close all unused file descriptors
858 ** We don't want them, we don't need them.
859 */
860 if ((i = open("/dev/null", O_RDONLY)) < 0)
861 {
862 /* TODO: BOO HISS */
863 dup2(STDERR_FILENO, STDIN_FILENO);
864 }
865 else if (i > STDIN_FILENO)
866 {
867 dup2(i, STDIN_FILENO);
868 close(i);
869 }
870 dup2(STDERR_FILENO, STDOUT_FILENO);
871 for (i = STDERR_FILENO + 1; i < num_fds; i++)
872 {
873 /* #ifdef __sgi */
874 #ifdef OS_IRIX
875 /* Alex Coventry says we need 4 & 7 too */
876 if (i == 4 || i == 7)
877 continue;
878 #endif
879 close(i);
880 }
881
882 /* Now set the correct num_fds */
883 r->num_fds = STDERR_FILENO + 1;
884 #ifdef OS_IRIX
885 r->num_fds = 7 + 1;
886 #endif
887 }
888
889
890 /* INTPROTO */
891 int
rxvt_xerror_handler(const Display * display,const XErrorEvent * event)892 rxvt_xerror_handler(const Display *display __attribute__((unused)), const XErrorEvent *event)
893 {
894 rxvt_t* r = rxvt_get_r();
895 char error_msg[1024];
896
897 XGetErrorText (r->Xdisplay, event->error_code, error_msg, 1023);
898 r->h->xerror_return = event->error_code;
899
900 if( !r->h->allowedxerror )
901 {
902 rxvt_msg (DBG_ERROR, DBG_INIT, "%s", error_msg);
903
904 #ifdef DEBUG_X
905 abort();
906 #endif
907 }
908
909 return 0; /* ignored anyway */
910 }
911
912
913 #ifdef TEXT_SHADOW
914 /* INTPROTO */
915 void
rxvt_init_shadow_mode(rxvt_t * r,const char * shadow_mode)916 rxvt_init_shadow_mode (rxvt_t* r, const char* shadow_mode)
917 {
918 if (
919 !shadow_mode || !STRCASECMP ("botright", shadow_mode)
920 || !STRCASECMP ("default", shadow_mode))
921 {
922 r->TermWin.shadow_mode = SHADOW_BOTRIGHT;
923 }
924 else if (!STRCASECMP ("botleft", shadow_mode))
925 {
926 r->TermWin.shadow_mode = SHADOW_BOTLEFT;
927 }
928 else if (!STRCASECMP ("topright", shadow_mode))
929 {
930 r->TermWin.shadow_mode = SHADOW_TOPRIGHT;
931 }
932 else if (!STRCASECMP ("topleft", shadow_mode))
933 {
934 r->TermWin.shadow_mode = SHADOW_TOPLEFT;
935 }
936 else if (!STRCASECMP ("top", shadow_mode))
937 {
938 r->TermWin.shadow_mode = SHADOW_TOP;
939 }
940 else if (!STRCASECMP ("bottom", shadow_mode))
941 {
942 r->TermWin.shadow_mode = SHADOW_BOTTOM;
943 }
944 else if (!STRCASECMP ("left", shadow_mode))
945 {
946 r->TermWin.shadow_mode = SHADOW_LEFT;
947 }
948 else if (!STRCASECMP ("right", shadow_mode))
949 {
950 r->TermWin.shadow_mode = SHADOW_RIGHT;
951 }
952 else if (!STRCASECMP ("none", shadow_mode))
953 {
954 r->TermWin.shadow_mode = SHADOW_NONE;
955 }
956 else /* no match == default */
957 {
958 r->TermWin.shadow_mode = SHADOW_NONE;
959 }
960 }
961 #endif
962
963
964 /*----------------------------------------------------------------------*/
965 /* EXTPROTO */
966 void
rxvt_set_jumpscroll(rxvt_t * r)967 rxvt_set_jumpscroll( rxvt_t *r )
968 {
969 if( r->h->rs[Rs_refreshLimit] )
970 {
971 r->h->refresh_limit = atol( r->h->rs[Rs_refreshLimit] );
972 if( r->h->refresh_limit < 0 )
973 r->h->refresh_limit = 0;
974 }
975 else
976 r->h->refresh_limit = DEFAULT_REFRESH_LIMIT;
977
978 if( r->h->rs[Rs_skipPages] )
979 {
980 r->h->skip_pages = atol( r->h->rs[Rs_skipPages] );
981 if( r->h->skip_pages <= 0 )
982 r->h->skip_pages = 1;
983 }
984 else
985 r->h->skip_pages = DEFAULT_SKIP_PAGES;
986 }
987
988
989 /* EXTPROTO */
990 const char**
rxvt_init_resources(rxvt_t * r,int argc,const char * const * argv)991 rxvt_init_resources(rxvt_t* r, int argc, const char *const *argv)
992 {
993 register int i, r_argc;
994 const char** cmd_argv;
995 const char** r_argv;
996 const char** rs;
997
998
999 /*
1000 * Look for -exec option. Find => split and make cmd_argv[] of command args
1001 */
1002 for( r_argc = 0; r_argc < argc; r_argc++ )
1003 if( !STRCMP(argv[r_argc], "-e") || !STRCMP(argv[r_argc], "-exec") )
1004 break;
1005
1006 r_argv = (const char**) rxvt_malloc( sizeof(char*) * (r_argc + 1) );
1007
1008 for( i = 0; i < r_argc; i++ )
1009 r_argv[i] = (const char*) argv[i];
1010 SET_NULL(r_argv[i]);
1011
1012 if (r_argc == argc)
1013 SET_NULL(cmd_argv);
1014 else
1015 {
1016 cmd_argv = (const char **)rxvt_malloc(sizeof(char*) * (argc - r_argc));
1017
1018 for (i = 0; i < argc - r_argc - 1; i++)
1019 cmd_argv[i] = (const char *)argv[i + r_argc + 1];
1020 SET_NULL(cmd_argv[i]);
1021 }
1022
1023 /* clear all resources */
1024 rs = r->h->rs;
1025 for (i = 0; i < NUM_RESOURCES;)
1026 SET_NULL(rs[i++]);
1027
1028 rs[Rs_name] = rxvt_r_basename( argv[0] );
1029
1030 /*
1031 * Open display, get options/resources and create the window
1032 */
1033 rxvt_get_options( r, r_argc, r_argv );
1034 rxvt_free( r_argv ); /* XXX memory leak? */
1035
1036 #ifdef LOCAL_X_IS_UNIX
1037 /*
1038 * 2008-04-29 gi1242: Force UNIX sockets for security (Gentoo Bug #219750)
1039 */
1040 if( IS_NULL( rs[Rs_display_name] ) )
1041 rs[Rs_display_name] = getenv( "DISPLAY" );
1042
1043 if( rs[Rs_display_name] && rs[Rs_display_name][0] == ':' )
1044 {
1045 char *val;
1046 int l = 5 + STRLEN(rs[Rs_display_name]);
1047 if (l <= 0 || l > 1024) /* possible integer overflow */
1048 l = 1024;
1049
1050 val = rxvt_malloc(l);
1051 STRCPY( val, "unix");
1052 STRNCAT( val, rs[Rs_display_name], l-5);
1053
1054 rs[Rs_display_name] = val;
1055 }
1056 #endif /* LOCAL_X_IS_UNIX */
1057
1058 rxvt_msg( DBG_INFO, DBG_INIT, "Open X display %s\n", rs[Rs_display_name] );
1059 r->Xdisplay = XOpenDisplay( rs[Rs_display_name] );
1060 if( IS_NULL(r->Xdisplay) )
1061 {
1062 rxvt_msg( DBG_ERROR, DBG_INIT, "Error opening display %s\n",
1063 rs[Rs_display_name] );
1064 exit( EXIT_FAILURE );
1065 }
1066
1067
1068 #ifdef DEBUG_X
1069 /*
1070 * Makes life a lot simpler when handling X events, as they are not cached,
1071 * but processed immediately.
1072 */
1073 XSynchronize( r->Xdisplay, True );
1074 #endif
1075
1076 /*
1077 * Always set XErrorHandler to our own error handler because sometimes
1078 * errors are legal! Our error handler will abort when errors are not
1079 * allowed.
1080 */
1081 XSetErrorHandler( (XErrorHandler) rxvt_xerror_handler );
1082
1083 /* Initialize all atoms after establishing connection to X */
1084 for (i = 0; i < NUM_XA; i++)
1085 r->h->xa[i] = XInternAtom( r->Xdisplay, xa_names[i], False );
1086
1087 rxvt_extract_resources( r, r->Xdisplay, rs[Rs_name] );
1088
1089 /*
1090 * set any defaults not already set
1091 */
1092 if( cmd_argv && cmd_argv[0] )
1093 {
1094 if( !rs[Rs_title] )
1095 rs[Rs_title] = rxvt_r_basename( cmd_argv[0] );
1096 if( !rs[Rs_iconName] )
1097 rs[Rs_iconName] = rs[Rs_title];
1098 }
1099 else
1100 {
1101 if( !rs[Rs_title] )
1102 rs[Rs_title] = rs[Rs_name];
1103 if( !rs[Rs_iconName] )
1104 rs[Rs_iconName] = rs[Rs_name];
1105 }
1106
1107 if( rs[Rs_maxTabWidth] )
1108 {
1109 register int tmp = atoi( rs[ Rs_maxTabWidth]);
1110 r->TermWin.maxTabWidth = ( tmp >=1 && tmp <= MAX_DISPLAY_TAB_TXT ) ?
1111 tmp : MAX_DISPLAY_TAB_TXT;
1112 }
1113 else
1114 /*
1115 * If we're using Xft, then we will probably also use a PFont. So we
1116 * should set this to the maximum possible.
1117 */
1118 r->TermWin.maxTabWidth =
1119 #ifdef XFT_SUPPORT
1120 ISSET_OPTION(r, Opt_xft) ? MAX_DISPLAY_TAB_TXT :
1121 #endif
1122 DEFAULT_DISPLAY_TAB_TXT;
1123
1124
1125 if( rs[Rs_minVisibleTabs] )
1126 {
1127 register int n = atoi( rs[Rs_minVisibleTabs] );
1128 r->TermWin.minVisibleTabs = (n >= 2 && n <= MAX_PAGES) ?
1129 n : DEFAULT_MIN_VISIBLE_TABS;
1130 }
1131 else r->TermWin.minVisibleTabs = DEFAULT_MIN_VISIBLE_TABS;
1132
1133 #ifndef NO_FRILLS
1134 if (rs[Rs_int_bwidth])
1135 {
1136 register int tmp = atoi( rs[Rs_int_bwidth] );
1137 r->TermWin.int_bwidth =( tmp >= 0 && tmp <= MAX_INTERNALBORDERWIDTH ) ?
1138 tmp : DEFAULT_INTERNALBORDERWIDTH;
1139 }
1140
1141 if (rs[Rs_ext_bwidth])
1142 {
1143 register int tmp = atoi( rs[Rs_ext_bwidth] );
1144 r->TermWin.ext_bwidth = (tmp >= 0 && tmp <= MAX_EXTERNALBORDERWIDTH) ?
1145 tmp : DEFAULT_EXTERNALBORDERWIDTH;
1146 }
1147 #endif
1148
1149 #ifndef NO_LINESPACE
1150 if (rs[Rs_lineSpace])
1151 {
1152 register int tmp = atoi( rs[Rs_lineSpace] );
1153 r->TermWin.lineSpace = (tmp >= 0 && tmp <= MAX_LINESPACE) ?
1154 tmp : DEFAULT_LINESPACE;
1155 }
1156 #endif
1157
1158 #ifdef POINTER_BLANK
1159 if (rs[Rs_pointerBlankDelay])
1160 {
1161 register int tmp = atoi( rs[Rs_pointerBlankDelay] );
1162 r->h->pointerBlankDelay = (tmp >= 0 && tmp <= MAX_BLANKDELAY) ?
1163 tmp : DEFAULT_BLANKDELAY;
1164 }
1165 #endif
1166
1167 /* Handle opacity of translucent window */
1168 if (rs[Rs_opacity])
1169 {
1170 register int tmp = atoi( rs[Rs_opacity] );
1171 r->TermWin.opacity = (tmp >= 0 && tmp <= 100) ? 100 - tmp : 0;
1172
1173 #ifdef TRANSPARENT
1174 if (
1175 IS_ATOM(r->h->xa[XA_NET_WM_WINDOW_OPACITY]) &&
1176 ISSET_OPTION(r, Opt_transparent)
1177 )
1178 {
1179 /* Override pseudo-transparent */
1180 UNSET_OPTION(r, Opt_transparent);
1181 }
1182 #endif
1183 }
1184 if (rs[Rs_opacityDegree])
1185 {
1186 register int tmp = atoi (rs[Rs_opacityDegree]);
1187 r->TermWin.opacity_degree = (tmp > 0 && tmp <= 100) ? tmp : 1;
1188 }
1189
1190 #ifdef TINTING_SUPPORT
1191 if (rs[Rs_shade])
1192 {
1193 register int shade;
1194 shade = atoi( rs[Rs_shade] );
1195 if (shade < 0 || shade > 100)
1196 shade = 100;
1197 r->TermWin.shade = 100 - shade;
1198 }
1199 #endif
1200
1201 rxvt_set_jumpscroll(r);
1202
1203 #ifdef TRANSPARENT
1204 if (rs[Rs_bgRefreshInterval])
1205 {
1206 register unsigned long interval = atol( rs[Rs_bgRefreshInterval] );
1207
1208 if( interval > 1000 ) interval = 1000;
1209 r->h->bgRefreshInterval = interval * 1000L; /* convert to micro-sec */
1210 }
1211 #endif
1212
1213 if (rs[Rs_fade])
1214 {
1215 register int fade;
1216 fade = atoi( rs[Rs_fade] );
1217
1218 /*
1219 * Fade levels of 0 will make the text completely black, so let's ignore
1220 * it.
1221 */
1222 if( fade <= 0 || fade > 100 )
1223 fade = 100;
1224 r->TermWin.fade = 100 - fade;
1225 }
1226 /* else r->TermWin.fade is 0 */
1227
1228 #ifdef CURSOR_BLINK
1229 if (rs[Rs_cursorBlinkInterval])
1230 {
1231 register long tmp = atol( rs[Rs_cursorBlinkInterval] );
1232 r->h->blinkInterval = (tmp >= MIN_BLINK_TIME && tmp <= MAX_BLINK_TIME) ? tmp : DEFAULT_BLINK_TIME;
1233 }
1234 /* convert msec to usec */
1235 r->h->blinkInterval *= 1000;
1236 #endif
1237
1238 #ifdef PRINTPIPE
1239 if (!rs[Rs_print_pipe])
1240 rs[Rs_print_pipe] = PRINTPIPE;
1241 #endif
1242 if (!rs[Rs_cutchars])
1243 rs[Rs_cutchars] = CUTCHARS;
1244
1245 #ifdef ACS_ASCII
1246 if( !rs[Rs_acs_chars] )
1247 rs[Rs_acs_chars] = ACS_CHARS;
1248 if( (i = STRLEN(rs[Rs_acs_chars])) < 0x20 )
1249 {
1250 char *val = rxvt_realloc( (void*) rs[Rs_acs_chars], 0x20 );
1251 for( ; i < 0x20; )
1252 val[i++] = ' ';
1253 rs[Rs_acs_chars] = val;
1254 }
1255 #endif
1256
1257 #ifndef NO_BACKSPACE_KEY
1258 if( !rs[Rs_backspace_key] )
1259 # ifdef DEFAULT_BACKSPACE
1260 r->h->key_backspace = DEFAULT_BACKSPACE;
1261 # else
1262 r->h->key_backspace = "DEC"; /* can toggle between \010 or \177 */
1263 # endif
1264 else
1265 {
1266 char* val = STRDUP(rs[Rs_backspace_key]);
1267 rxvt_str_trim( val );
1268 rxvt_str_escaped( val );
1269 r->h->key_backspace = val;
1270 }
1271 #endif
1272 #ifndef NO_DELETE_KEY
1273 if( !rs[Rs_delete_key] )
1274 # ifdef DEFAULT_DELETE
1275 r->h->key_delete = DEFAULT_DELETE;
1276 # else
1277 r->h->key_delete = "\033[3~";
1278 # endif
1279 else
1280 {
1281 char *val = STRDUP( rs[Rs_delete_key] );
1282 rxvt_str_trim( val );
1283 rxvt_str_escaped( val );
1284 r->h->key_delete = val;
1285 }
1286 #endif
1287 if( rs[Rs_answerbackstring] )
1288 {
1289 rxvt_str_trim( (char*) rs[Rs_answerbackstring] );
1290 rxvt_str_escaped( (char*) rs[Rs_answerbackstring] );
1291 }
1292
1293 if( rs[Rs_selectstyle] )
1294 {
1295 if( STRNCASECMP( rs[Rs_selectstyle], "oldword", 7 ) == 0 )
1296 r->selection_style = OLD_WORD_SELECT;
1297 #ifndef NO_OLD_SELECTION
1298 else if( STRNCASECMP( rs[Rs_selectstyle], "old", 3 ) == 0 )
1299 r->selection_style = OLD_SELECT;
1300 #endif
1301 }
1302
1303
1304 /* Set default X11 fonts */
1305 rxvt_set_default_font_x11( r );
1306 #ifdef XFT_SUPPORT
1307 if( rs[Rs_xftsz] )
1308 {
1309 int sz = atoi( rs[Rs_xftsz] );
1310 r->TermWin.xftsize = (sz >= MIN_XFT_FONT_SIZE) ? sz : MIN_XFT_FONT_SIZE;
1311 }
1312 else /* default xft font size */
1313 r->TermWin.xftsize = DEFAULT_XFT_FONT_SIZE;
1314
1315 if (rs[Rs_xftpsz])
1316 {
1317 int sz = atoi (rs[Rs_xftpsz]);
1318 r->TermWin.xftpsize = (sz >= MIN_XFT_FONT_SIZE) ?
1319 sz : MIN_XFT_FONT_SIZE;
1320 }
1321 else /* default xft Pfont size */
1322 r->TermWin.xftpsize = DEFAULT_XFT_PFONT_SIZE;
1323
1324 # ifdef MULTICHAR_SET
1325 if (rs[Rs_xftmsz])
1326 {
1327 int sz = (int) atof (rs[Rs_xftmsz]);
1328 r->TermWin.xftmsize = (sz >= MIN_XFT_FONT_SIZE) ?
1329 sz : MIN_XFT_FONT_SIZE;
1330 }
1331 else /* default xft font size */
1332 r->TermWin.xftmsize = DEFAULT_XFT_FONT_SIZE;
1333 # endif /* MULTICHAR_SET */
1334
1335 /* Set default Freetype fonts */
1336 rxvt_set_default_font_xft (r);
1337 #endif /* XFT_SUPPORT */
1338
1339
1340 #ifdef TEXT_SHADOW
1341 rxvt_init_shadow_mode (r, rs[Rs_textShadowMode]);
1342 #endif
1343
1344 #ifdef XTERM_REVERSE_VIDEO
1345 /* this is how xterm implements reverseVideo */
1346 if (ISSET_OPTION(r, Opt_reverseVideo))
1347 {
1348 if (!rs[Rs_color + Color_fg])
1349 rs[Rs_color + Color_fg] = def_colorName[Color_bg];
1350 if (!rs[Rs_color + Color_bg])
1351 rs[Rs_color + Color_bg] = def_colorName[Color_fg];
1352
1353 for (i = 0; i < MAX_PROFILES; i++)
1354 {
1355 int vtfg = Rs_foreground + i;
1356 int vtbg = Rs_background + i;
1357
1358 char* fg = (char*) rs[vtfg];
1359 char* bg = (char*) rs[vtbg];
1360
1361 /* foreground color of i terminal */
1362 if (ISSET_VTFG(r, i))
1363 rs[vtfg] = ISSET_VTBG(r, i) ? bg :
1364 def_colorName[Color_bg];
1365 /* background color of i terminal */
1366 if (ISSET_VTBG(r, i))
1367 rs[vtbg] = ISSET_VTFG(r, i) ? fg :
1368 def_colorName[Color_fg];
1369 }
1370 }
1371 #endif
1372
1373 for (i = 0; i < NRS_COLORS; i++)
1374 if (!rs[Rs_color + i])
1375 rs[Rs_color + i] = def_colorName[i];
1376
1377 #ifndef XTERM_REVERSE_VIDEO
1378 /* this is how we implement reverseVideo */
1379 if (ISSET_OPTION(r, Opt_reverseVideo))
1380 {
1381 if (!rs[Rs_color + Color_fg])
1382 rs[Rs_color + Color_fg] = def_colorName[Color_fg];
1383 if (!rs[Rs_color + Color_bg])
1384 rs[Rs_color + Color_bg] = def_colorName[Color_bg];
1385
1386 SWAP_IT(rs[Rs_color + Color_fg], rs[Rs_color + Color_bg], const char *);
1387
1388 for (i = 0; i < MAX_PROFILES; i++)
1389 {
1390 int vtfg = Rs_foreground + i;
1391 int vtbg = Rs_background + i;
1392 if (!rs[vtfg])
1393 rs[vtfg] = def_colorName[Color_fg];
1394 if (!rs[vtbg])
1395 rs[vtbg] = def_colorName[Color_bg];
1396
1397 SWAP_IT(rs[vtfg], rs[vtbg], const char*);
1398 }
1399 }
1400 #endif
1401
1402 /* convenient aliases for setting fg/bg to colors */
1403 rxvt_color_aliases(r, Color_fg);
1404 rxvt_color_aliases(r, Color_bg);
1405 #ifndef NO_CURSORCOLOR
1406 rxvt_color_aliases(r, Color_cursor);
1407 rxvt_color_aliases(r, Color_cursor2);
1408 #endif /* NO_CURSORCOLOR */
1409 rxvt_color_aliases(r, Color_pointer);
1410 rxvt_color_aliases(r, Color_border);
1411 #ifndef NO_BOLD_UNDERLINE_REVERSE
1412 rxvt_color_aliases(r, Color_BD);
1413 rxvt_color_aliases(r, Color_UL);
1414 rxvt_color_aliases(r, Color_RV);
1415 #endif /* ! NO_BOLD_UNDERLINE_REVERSE */
1416
1417 /*
1418 * On startup, use autohideTabbar to override hideTabbar. Thus on startup,
1419 * using autohideTabbar will only display the tabbar if there are multiple
1420 * tabs. The user can hide / show the tabbar using a macro at will.
1421 */
1422 if(ISSET_OPTION(r, Opt2_autohideTabbar))
1423 SET_OPTION(r, Opt2_hideTabbar);
1424
1425 /* Cleanup the macro list */
1426 rxvt_cleanup_macros( r );
1427
1428
1429 /*
1430 * Profile settings.
1431 */
1432 for( i=0; i < MAX_PROFILES; i++ )
1433 {
1434 /* Set saveLines */
1435 if( r->h->rs[Rs_saveLines + i] )
1436 {
1437 int tmp = atoi( r->h->rs[Rs_saveLines + i] );
1438
1439 r->profile[i].saveLines = ( tmp >= 0 && tmp <= MAX_SAVELINES ) ?
1440 tmp : DEFAULT_SAVELINES;
1441 }
1442 else
1443 r->profile[i].saveLines = ( i > 0 ) ? r->profile[0].saveLines :
1444 DEFAULT_SAVELINES;
1445
1446 /* Set holdOption */
1447 if( r->h->rs[Rs_holdExit + i] )
1448 {
1449 const char *s = r->h->rs[Rs_holdExit + i];
1450
1451 /* Backward compatibility hack */
1452 if(
1453 !STRCASECMP( s, "true" ) ||
1454 !STRCASECMP( s, "yes" ) ||
1455 !STRCASECMP( s, "on" )
1456 )
1457 r->profile[i].holdOption = HOLD_ALWAYSBIT;
1458 else
1459 r->profile[i].holdOption = strtoul( s, NULL, 0 );
1460 }
1461 else
1462 r->profile[i].holdOption = (i > 0) ? r->profile[0].holdOption :
1463 (HOLD_STATUSBIT|HOLD_NORMALBIT);
1464 } /* for(i) */
1465
1466 if( !r->h->rs[Rs_holdExitTtl] )
1467 r->h->rs[Rs_holdExitTtl] = "(Done) %t";
1468
1469 if( !r->h->rs[Rs_holdExitTxt] )
1470 r->h->rs[Rs_holdExitTxt] = "\n\n\r\e[31m"
1471 "Process exited %N with status %S. "
1472 "Press any key to close tab.\e[0m";
1473
1474 #ifdef OS_LINUX
1475 if( !r->h->rs[Rs_cwd] )
1476 r->h->rs[Rs_cwd] = ".";
1477 #endif
1478
1479 #ifndef NO_BEEP
1480 if( r->h->rs[Rs_vBellDuration] )
1481 r->TermWin.vBellDuration =
1482 1000000ul * strtoul( r->h->rs[Rs_vBellDuration], NULL, 0 );
1483 else
1484 r->TermWin.vBellDuration = 0;
1485 #endif
1486
1487
1488 return cmd_argv;
1489 }
1490
1491 /*----------------------------------------------------------------------*/
1492 /* EXTPROTO */
1493 void
rxvt_init_env(rxvt_t * r)1494 rxvt_init_env(rxvt_t *r)
1495 {
1496 int i;
1497 unsigned int u;
1498 char* val;
1499
1500
1501 #ifdef DISPLAY_IS_IP
1502 /* Fixup display_name for export over pty to any interested
1503 ** terminal clients via "ESC[7n" (e.g. shells). Note we use
1504 ** the pure IP number (for the first non-loopback interface)
1505 ** that we get from rxvt_network_display(). This is more
1506 ** "name-resolution-portable", if you will, and probably allows
1507 ** for faster x-client startup if your name server is beyond
1508 ** a slow link or overloaded at client startup. Of course that
1509 ** only helps the shell's child processes, not us.
1510 **
1511 ** Giving out the display_name also affords a potential
1512 ** security hole
1513 */
1514 val = rxvt_network_display(r->h->rs[Rs_display_name]);
1515 r->h->rs[Rs_display_name] = (const char *)val;
1516 if (IS_NULL(val))
1517 #endif /* DISPLAY_IS_IP */
1518 val = XDisplayString(r->Xdisplay);
1519 if (IS_NULL(r->h->rs[Rs_display_name]))
1520 r->h->rs[Rs_display_name] = val; /* use broken `:0' value */
1521
1522 i = STRLEN(val) + 9;
1523 if (i <= 0 || i > 1024) /* possible integer overflow */
1524 i = 1024;
1525 r->h->env_display = rxvt_malloc(i * sizeof(char));
1526 STRCPY (r->h->env_display, "DISPLAY=");
1527 STRNCAT (r->h->env_display, val, i-9);
1528 r->h->env_display[i-1] = (char) 0;
1529
1530 /* avoiding the math library:
1531 * i = (int)(ceil(log10((unsigned int)r->TermWin.parent))) */
1532 for (i = 0, u = (unsigned int)r->TermWin.parent; u; u /= 10, i++)
1533 ;
1534 MAX_IT(i, 1);
1535 r->h->env_windowid = rxvt_malloc((i + 10) * sizeof(char));
1536
1537 sprintf(r->h->env_windowid, "WINDOWID=%u",
1538 (unsigned int)r->TermWin.parent);
1539
1540 /*
1541 ** add entries to the environment:
1542 ** @ DISPLAY: in case we started with -display
1543 ** @ WINDOWID: X window id number of the window
1544 ** @ COLORTERM: terminal sub-name and also indicates its color
1545 ** @ TERM: terminal name
1546 ** @ TERMINFO: path to terminfo directory
1547 */
1548 #ifdef HAVE_PUTENV
1549 putenv(r->h->env_display);
1550 putenv(r->h->env_windowid);
1551
1552 # ifdef RXVT_TERMINFO
1553 putenv("TERMINFO=" RXVT_TERMINFO);
1554 # endif
1555 if (XDEPTH <= 2)
1556 putenv("COLORTERM=" COLORTERMENV "-mono");
1557 else
1558 putenv("COLORTERM=" COLORTERMENVFULL);
1559 if (NOT_NULL(r->h->rs[Rs_term_name]))
1560 {
1561 int l = 6 + STRLEN(r->h->rs[Rs_term_name]);
1562 if (l <= 0 || l > 1024) /* possible integer overflow */
1563 l = 1024;
1564 r->h->env_term = rxvt_malloc(l * sizeof(char));
1565 STRCPY (r->h->env_term, "TERM=");
1566 STRNCAT (r->h->env_term, r->h->rs[Rs_term_name], l-6);
1567 r->h->env_term[l-1] = (char) 0;
1568 putenv(r->h->env_term);
1569 }
1570 else
1571 putenv("TERM=" TERMENV);
1572 #endif /* HAVE_PUTENV */
1573
1574 #ifdef HAVE_UNSETENV
1575 /* avoid passing old settings and confusing term size */
1576 unsetenv("LINES");
1577 unsetenv("COLUMNS");
1578 unsetenv("TERMCAP"); /* terminfo should be okay */
1579 #endif /* HAVE_UNSETENV */
1580
1581 /*
1582 ** allocate environment variable for MRXVT_TABTITLE, we will
1583 ** use it in rxvt_create_termwin later for each tab terminal
1584 */
1585 r->h->env_tabtitle = rxvt_malloc(sizeof(TABTITLEENV) + MAX_TAB_TXT + 1);
1586 }
1587
1588 /*----------------------------------------------------------------------*/
1589 /*
1590 * This is more or less stolen straight from XFree86 xterm.
1591 * This should support all European type languages.
1592 */
1593 /* EXTPROTO */
1594 void
rxvt_init_xlocale(rxvt_t * r)1595 rxvt_init_xlocale(rxvt_t *r)
1596 {
1597 #ifdef USE_XIM
1598 if (IS_NULL(r->h->locale))
1599 rxvt_msg (DBG_ERROR, DBG_INIT, "Setting locale failed.");
1600 else
1601 {
1602 XChangeProperty(r->Xdisplay, r->TermWin.parent,
1603 r->h->xa[XA_WM_LOCALE_NAME], XA_STRING, 8, PropModeReplace,
1604 (unsigned char *)r->h->locale, STRLEN(r->h->locale));
1605
1606 if (XSupportsLocale() != True)
1607 {
1608 rxvt_msg (DBG_ERROR, DBG_INIT, "The locale is not supported by Xlib");
1609 return;
1610 }
1611 rxvt_IM_set_fontset (r, 0);
1612
1613 /* see if we can connect yet */
1614 rxvt_IM_init_callback (r->Xdisplay, NULL, NULL);
1615
1616 /* To avoid Segmentation Fault in C locale: Solaris only? */
1617 if (STRCMP(r->h->locale, "C"))
1618 XRegisterIMInstantiateCallback(r->Xdisplay, NULL, NULL,
1619 NULL, rxvt_IM_init_callback, NULL);
1620 }
1621 #endif
1622 }
1623
1624 /*----------------------------------------------------------------------*/
1625
1626 /* EXTPROTO */
1627 #ifdef USE_FIFO
1628 void
rxvt_init_fifo(rxvt_t * r)1629 rxvt_init_fifo( rxvt_t *r )
1630 {
1631 unlink( r->fifo_name );
1632 mkfifo( r->fifo_name, 0600 );
1633
1634 /*
1635 * Create the fifo in read write mode. If not, when no clients have the
1636 * fifo open, select() will claim our fifo has data pending and return.
1637 */
1638 r->fifo_fd = open( r->fifo_name, O_RDONLY|O_NDELAY );
1639 if( r->fifo_fd == -1 )
1640 UNSET_OPTION( r, Opt_useFifo );
1641 else
1642 MAX_IT( r->num_fds, r->fifo_fd + 1);
1643
1644 /* Reset the fifo buffer */
1645 r->fbuf_ptr = r->fifo_buf;
1646 }
1647 #endif
1648
1649 /* EXTPROTO */
1650 void
rxvt_init_command(rxvt_t * r)1651 rxvt_init_command(rxvt_t* r)
1652 {
1653 /*
1654 * Initialize the command connection. This should be called after the X
1655 * server connection is established.
1656 */
1657 struct sigaction act;
1658
1659 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "%s()\n", __func__));
1660
1661
1662 /*
1663 * Enable delete window protocol so that if the top-level window of the
1664 * terminal is destroyed by the Session Manager, we can receive a
1665 * ClientMessage event and do something gracefully.
1666 */
1667 XSetWMProtocols (r->Xdisplay, r->TermWin.parent,
1668 &(r->h->xa[XA_WMDELETEWINDOW]), 1);
1669
1670 #ifdef META8_OPTION
1671 r->h->meta_char = (ISSET_OPTION(r, Opt_meta8) ? 0x80 : C0_ESC);
1672 #endif
1673 rxvt_get_ourmods(r);
1674
1675 #ifdef GREEK_SUPPORT
1676 greek_init();
1677 #endif
1678
1679 r->Xfd = XConnectionNumber(r->Xdisplay);
1680 #ifdef USE_FIFO
1681 if( ISSET_OPTION( r, Opt_useFifo ) )
1682 rxvt_init_fifo( r );
1683 else
1684 r->fifo_fd = -1;
1685 #endif
1686
1687 #ifdef CURSOR_BLINK
1688 if (ISSET_OPTION(r, Opt_cursorBlink))
1689 (void)gettimeofday(&r->h->lastcursorchange, NULL);
1690 #endif
1691
1692 /*
1693 * Gracefully exit on term signals.
1694 */
1695 act.sa_handler = rxvt_Exit_signal;
1696 act.sa_flags = 0;
1697 sigemptyset (&act.sa_mask);
1698
1699 #ifndef OS_SVR4
1700 sigaction( SIGINT , &act, NULL);
1701 #endif
1702 sigaction( SIGQUIT, &act, NULL);
1703 sigaction( SIGTERM, &act, NULL);
1704
1705 /*
1706 * 2006-04-28 gi1242: Ignore HUP signals. We sometimes receive this if bash
1707 * is killed. Chances are that we don't have to exit ...
1708 */
1709 act.sa_handler = SIG_IGN;
1710 sigaction( SIGHUP, &act, NULL);
1711
1712 #ifdef PRINTPIPE
1713 /*
1714 * 2006-04-28 gi1242: If there is an error opening the printer command, then
1715 * we'll get SIGPIPE. If not handled, mrxvt will exit.
1716 *
1717 * There's nothing we really need to do on broken pipes, so just ignore
1718 * SIGPIPE for now.
1719 */
1720 sigaction( SIGPIPE, &act, NULL);
1721 #endif
1722
1723 act.sa_handler = rxvt_Child_signal;
1724 sigaction (SIGCHLD, &act, NULL);
1725 }
1726
1727
1728 /* EXTPROTO */
1729 void
rxvt_fade_color(rxvt_t * r,const XColor * xcol,unsigned long * pix_return,XftColor * xft_return)1730 rxvt_fade_color( rxvt_t* r, const XColor *xcol,
1731 unsigned long *pix_return,
1732 # ifdef XFT_SUPPORT
1733 XftColor *xft_return
1734 # else
1735 void *xft_return
1736 # endif
1737 )
1738 {
1739 if( r->TermWin.fade )
1740 {
1741 XColor faded_xcol;
1742
1743 faded_xcol.red = (xcol->red / 100) * r->TermWin.fade;
1744 faded_xcol.green = (xcol->green / 100) * r->TermWin.fade;
1745 faded_xcol.blue = (xcol->blue / 100) * r->TermWin.fade;
1746
1747 rxvt_alloc_color( r, &faded_xcol, "Faded" );
1748
1749 *pix_return = faded_xcol.pixel;
1750 # ifdef XFT_SUPPORT
1751 if( NOT_NULL( xft_return ) )
1752 rxvt_alloc_xft_color( r, &faded_xcol, xft_return );
1753
1754 # endif
1755 }
1756 }
1757
1758
1759 #define setChanged( a, b ) \
1760 if( (a) != (b) ) {(a) = (b); changed = 1;}
1761 #define setChangedXft( a, b ) \
1762 if( (a).pixel != (b).pixel ) { (a) = (b); changed = 1;}
1763 /*
1764 * Sets r->pixColors[Color_fg] / etc to the correct color (depending on the ufbg
1765 * color, off focus fading and weather we have focus or not).
1766 */
1767 /* EXTPROTO */
1768 int
rxvt_set_fgbg_colors(rxvt_t * r,int page)1769 rxvt_set_fgbg_colors( rxvt_t *r, int page )
1770 {
1771 int changed = 0;
1772
1773 rxvt_dbgmsg(( DBG_DEBUG, DBG_INIT, "%s(r, page=%d)"
1774 ": fgbg_tabnum=%d, globalTabNum=%d\n", __func__, page,
1775 r->fgbg_tabnum, PVTS(r, page)->globalTabNum));
1776
1777 if(
1778 r->fgbg_tabnum == PVTS(r, page)->globalTabNum &&
1779 (
1780 r->TermWin.fade ||
1781 !ISSET_PIXCOLOR( r->h, Color_ufbg ) ||
1782 (
1783 /*
1784 * If we dont have fading, but have ufbg, then make sure that
1785 * Color_bg points to the correct color.
1786 */
1787 r->TermWin.focus ?
1788 ( r->pixColors[Color_bg] == PVTS(r, page)->p_bg ) :
1789 ( r->pixColors[Color_bg] == r->pixColors[Color_ufbg] )
1790 )
1791 )
1792 )
1793 return 0; /* No change */
1794
1795 setChanged( r->pixColorsFocus[Color_fg], PVTS( r, page)->p_fg );
1796 #ifdef XFT_SUPPORT
1797 if( ISSET_OPTION( r, Opt_xft ) )
1798 setChangedXft( r->xftColorsFocus[Color_fg], PVTS(r, page)->p_xftfg );
1799 #endif
1800
1801 if( r->TermWin.fade )
1802 {
1803 /* Ignore ufbg, and use faded colors */
1804 setChanged( r->pixColorsFocus[Color_bg], PVTS(r, page)->p_bg );
1805
1806 setChanged( r->pixColorsUnfocus[Color_fg], PVTS(r, page)->p_fgfade );
1807 setChanged( r->pixColorsUnfocus[Color_bg], PVTS(r, page)->p_bgfade );
1808
1809 #ifdef XFT_SUPPORT
1810 if( ISSET_OPTION( r, Opt_xft ) )
1811 {
1812 setChangedXft( r->xftColorsFocus[Color_bg],
1813 PVTS(r, page)->p_xftbg );
1814
1815 setChangedXft( r->xftColorsUnfocus[Color_fg],
1816 PVTS(r, page)->p_xftfgfade );
1817 setChangedXft( r->xftColorsUnfocus[Color_bg],
1818 PVTS(r, page)->p_xftbgfade );
1819 }
1820 #endif
1821 }
1822
1823 else if( ISSET_PIXCOLOR( r->h, Color_ufbg ) && !r->TermWin.focus )
1824 {
1825 /* No fading. But use Color_ufbg */
1826 setChanged( r->pixColorsFocus[Color_bg],
1827 r->pixColorsFocus[Color_ufbg] );
1828 #ifdef XFT_SUPPORT
1829 if( ISSET_OPTION( r, Opt_xft ) )
1830 setChangedXft( r->xftColorsFocus[Color_bg],
1831 r->xftColorsFocus[Color_ufbg] );
1832 #endif
1833 }
1834
1835 else
1836 {
1837 /* Use fgbg from profile */
1838 setChanged( r->pixColorsFocus[Color_bg],
1839 PVTS(r, page)->p_bg );
1840 #ifdef XFT_SUPPORT
1841 if( ISSET_OPTION( r, Opt_xft ) )
1842 setChangedXft( r->xftColorsFocus[Color_bg],
1843 PVTS(r, page)->p_xftbg );
1844 #endif
1845 }
1846
1847 r->fgbg_tabnum = PVTS( r, page )->globalTabNum;
1848
1849 rxvt_dbgmsg(( DBG_DEBUG, DBG_INIT, "%s(r, page=%d) returning %d\n",
1850 __func__, page, changed ));
1851 return changed; /* Changed */
1852 }
1853 #undef setChanged
1854 #undef setChangedXft
1855
1856
1857 void
rxvt_copy_color(rxvt_t * r,int dst_index,int src_index)1858 rxvt_copy_color( rxvt_t *r, int dst_index, int src_index )
1859 {
1860 r->pixColorsFocus[ dst_index ] = r->pixColorsFocus[ src_index ];
1861
1862 if( r->TermWin.fade )
1863 r->pixColorsUnfocus[ dst_index ] = r->pixColorsUnfocus[ src_index ];
1864
1865 #ifdef XFT_SUPPORT
1866 if( ISSET_OPTION( r, Opt_xft ) )
1867 {
1868 r->xftColorsFocus[ dst_index ] = r->xftColorsFocus[ src_index ];
1869
1870 if( r->TermWin.fade )
1871 r->xftColorsUnfocus[ dst_index ] = r->xftColorsUnfocus[ src_index ];
1872 }
1873 #endif
1874
1875 SET_PIXCOLOR( r->h, dst_index );
1876 }
1877
1878
1879 void
rxvt_set_color(rxvt_t * r,int cIndex,const XColor * xcol)1880 rxvt_set_color( rxvt_t *r, int cIndex, const XColor *xcol )
1881 {
1882 /* xcol must contain an ALLOCATED color */
1883 r->pixColorsFocus[cIndex] = xcol->pixel;
1884 #ifdef XFT_SUPPORT
1885 if( ISSET_OPTION( r, Opt_xft ) )
1886 rxvt_alloc_xft_color( r, xcol, &r->xftColorsFocus[cIndex] );
1887 #endif
1888
1889 if( r->TermWin.fade )
1890 {
1891 if( cIndex == Color_pointer )
1892 {
1893 /* Don't fade these colors */
1894 r->pixColorsUnfocus[cIndex] = r->pixColorsFocus[cIndex];
1895 #ifdef XFT_SUPPORT
1896 if( ISSET_OPTION( r, Opt_xft ) )
1897 r->xftColorsUnfocus[cIndex] = r->xftColorsFocus[cIndex];
1898 #endif
1899 }
1900
1901 else
1902 rxvt_fade_color( r, xcol, &r->pixColorsUnfocus[cIndex],
1903 #ifdef XFT_SUPPORT
1904 ISSET_OPTION(r, Opt_xft) ? &r->xftColorsUnfocus[cIndex] : NULL
1905 #else
1906 NULL
1907 #endif
1908 );
1909 }
1910
1911 SET_PIXCOLOR( r->h, cIndex );
1912 }
1913
1914
1915 /*
1916 * XXX 2006-05-24 gi1242: Should allocate Xft colors only if Opt_xft is set. In
1917 * that case we should avoid allocating XColors, since we can always access them
1918 * through xftcolor.pixel.
1919 */
1920 /* INTPROTO */
1921 void
rxvt_init_colors(rxvt_t * r)1922 rxvt_init_colors( rxvt_t *r )
1923 {
1924 register int i;
1925
1926 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "%s()\n", __func__));
1927
1928 /* Initialize fg/bg colors for each profile */
1929 for (i = 0; i < MAX_PROFILES; i++)
1930 {
1931 XColor xcol;
1932 int vtfg = Rs_foreground + i;
1933 int vtbg = Rs_background + i;
1934
1935 if( !ISSET_VTFG( r, i ) )
1936 r->h->rs[vtfg] = ISSET_VTFG( r, 0 ) ?
1937 r->h->rs[Rs_foreground] : def_colorName[ Color_fg ];
1938 if( !ISSET_VTBG( r, i ) )
1939 r->h->rs[vtbg] = ISSET_VTBG( r, 0 ) ?
1940 r->h->rs[Rs_background] : def_colorName[ Color_bg ];
1941
1942 /* foreground color of i terminal */
1943 if( rxvt_parse_alloc_color(r, &xcol, r->h->rs[vtfg]) )
1944 {
1945 VTFG(r, i) = xcol.pixel;
1946
1947 #ifdef XFT_SUPPORT
1948 rxvt_alloc_xft_color( r, &xcol, &(VTXFTFG(r, i)) );
1949 rxvt_fade_color( r, &xcol, &VTFG_FADE(r, i), &VTXFTFG_FADE(r, i) );
1950 #else
1951 rxvt_fade_color( r, &xcol, &VTFG_FADE(r, i), NULL );
1952 #endif /* XFT_SUPPORT */
1953 }
1954
1955 else
1956 {
1957 rxvt_msg (DBG_ERROR, DBG_INIT, "Could not alloc foreground color of profile %d",
1958 i );
1959 if( i == 0 )
1960 /* Need default fg/bg */
1961 exit( EXIT_FAILURE );
1962
1963 /* Use foreground from profie 0 */
1964 VTFG( r, i ) = VTFG( r, 0 );
1965 VTFG_FADE( r, i ) = VTFG_FADE( r, 0 );
1966
1967 #ifdef XFT_SUPPORT
1968 VTXFTFG( r, i ) = VTXFTFG( r, 0 );
1969 VTXFTFG_FADE( r, i ) = VTXFTFG_FADE( r, 0 );
1970 #endif
1971 }
1972
1973 /* background color of i terminal */
1974 if( rxvt_parse_alloc_color(r, &xcol, r->h->rs[vtbg]) )
1975 {
1976 VTBG(r, i) = xcol.pixel;
1977
1978 #ifdef XFT_SUPPORT
1979 rxvt_alloc_xft_color( r, &xcol, &(VTXFTBG(r, i)) );
1980 rxvt_fade_color( r, &xcol, &VTBG_FADE(r, i), &VTXFTBG_FADE(r, i) );
1981 #else
1982 rxvt_fade_color( r, &xcol, &VTBG_FADE(r, i), NULL );
1983 #endif /* XFT_SUPPORT */
1984 }
1985
1986 else
1987 {
1988 rxvt_msg (DBG_ERROR, DBG_INIT, "Could not alloc background color of profile %d",
1989 i );
1990 if( i == 0 )
1991 /* Need default fg/bg */
1992 exit( EXIT_FAILURE );
1993
1994 /* Use background from profie 0 */
1995 VTBG( r, i ) = VTBG( r, 0 );
1996 VTBG_FADE( r, i ) = VTBG_FADE( r, 0 );
1997
1998 #ifdef XFT_SUPPORT
1999 VTXFTBG( r, i ) = VTXFTBG( r, 0 );
2000 VTXFTBG_FADE( r, i ) = VTXFTBG_FADE( r, 0 );
2001 #endif
2002 }
2003 }
2004
2005 /* Set foreground / background colors */
2006 r->pixColorsFocus[ Color_fg ] = VTFG( r, 0 );
2007 r->pixColorsFocus[ Color_bg ] = VTBG( r, 0 );
2008
2009 if( r->TermWin.fade )
2010 {
2011 r->pixColorsUnfocus[ Color_fg ] = VTFG_FADE( r, 0 );
2012 r->pixColorsUnfocus[ Color_bg ] = VTBG_FADE( r, 0 );
2013 }
2014
2015 #ifdef XFT_SUPPORT
2016 if( ISSET_OPTION( r, Opt_xft ) )
2017 {
2018 r->xftColorsFocus[ Color_fg ] = VTXFTFG( r, 0 );
2019 r->xftColorsFocus[ Color_bg ] = VTXFTBG( r, 0 );
2020
2021 if( r->TermWin.fade )
2022 {
2023 r->xftColorsUnfocus[ Color_fg ] = VTXFTFG( r, 0 );
2024 r->xftColorsUnfocus[ Color_bg ] = VTXFTBG( r, 0 );
2025 }
2026 }
2027 #endif
2028
2029 r->fgbg_tabnum = -1; /* fg/bg corresponds to profile 0, not any
2030 particular tab during initialization. */
2031
2032
2033 /*
2034 * Allocate generic colors.
2035 */
2036 for (i = minCOLOR; i < (XDEPTH <= 2 ? 2 : NRS_COLORS); i++)
2037 {
2038 XColor xcol;
2039
2040 if( IS_NULL(r->h->rs[Rs_color + i]) )
2041 continue;
2042
2043 if( !rxvt_parse_alloc_color(r, &xcol, r->h->rs[Rs_color + i]) )
2044 {
2045 if( r->h->rs[Rs_color+i] != def_colorName[i] )
2046 {
2047 rxvt_msg (DBG_ERROR, DBG_INIT, "Could not allocate color '%s'\n",
2048 r->h->rs[Rs_color + i] );
2049
2050 /* Try again with default color */
2051 r->h->rs[Rs_color + i] = def_colorName[i];
2052 i--;
2053 continue;
2054 }
2055
2056 /*
2057 * Unable to alloc even the default color. Fall back to fg/bg.
2058 */
2059 switch( i )
2060 {
2061 #ifndef NO_CURSORCOLOR
2062 case Color_cursor2:
2063 #endif /* !NO_CURSORCOLOR */
2064 case Color_pointer:
2065 rxvt_copy_color( r, i, Color_fg );
2066 break;
2067
2068 default:
2069 rxvt_copy_color( r, i, Color_bg );
2070 break;
2071 }
2072 }
2073
2074 else
2075 {
2076 /*
2077 * Succeeded allocating the color. Store it in pixColors.
2078 */
2079 rxvt_set_color( r, i, &xcol );
2080 }
2081 } /* for(i) */
2082
2083
2084 /*
2085 * Allocate colors which are essential if they have not been allocated.
2086 */
2087 if( XDEPTH <= 2 || !ISSET_PIXCOLOR( r->h, Color_pointer ) )
2088 {
2089 /*
2090 * NOTE: Fading should be disabled for low depths. And the pointer color
2091 * should not be faded.
2092 */
2093 r->pixColorsFocus[Color_pointer] = VTFG(r, 0);
2094 if( r->TermWin.fade )
2095 r->pixColorsUnfocus[Color_pointer] = VTFG(r, 0);
2096 #ifdef XFT_SUPPORT
2097 if( ISSET_OPTION( r, Opt_xft ) )
2098 {
2099 r->xftColorsFocus[Color_pointer] = VTXFTFG(r, 0);
2100 if( r->TermWin.fade )
2101 r->xftColorsUnfocus[Color_pointer] = VTXFTFG(r, 0);
2102 }
2103 #endif
2104 SET_PIXCOLOR( r->h, Color_pointer );
2105 }
2106
2107 if( XDEPTH <= 2 || !ISSET_PIXCOLOR( r->h, Color_border ) )
2108 rxvt_copy_color( r, Color_border, Color_fg );
2109
2110
2111 /*
2112 * get scrollBar/menuBar shadow colors
2113 *
2114 * The calculations of topShadow/bottomShadow values are adapted from the
2115 * fvwm window manager.
2116 */
2117 #ifdef KEEP_SCROLLCOLOR
2118 if (XDEPTH <= 2) /* Monochrome */
2119 {
2120 rxvt_copy_color( r, Color_scroll, Color_fg );
2121 rxvt_copy_color( r, Color_topShadow, Color_bg );
2122 rxvt_copy_color( r, Color_bottomShadow, Color_bg );
2123 }
2124
2125 else
2126 {
2127 XColor xcol[3];
2128 /*
2129 * xcol[0] == white
2130 * xcol[1] == top shadow
2131 * xcol[2] == bot shadow
2132 */
2133
2134 xcol[1].pixel = r->pixColorsFocus[Color_scroll];
2135 # ifdef PREFER_24BIT
2136 xcol[0].red = xcol[0].green = xcol[0].blue = 0xffffu;
2137 rxvt_alloc_color( r, &(xcol[0]), "White" );
2138 XQueryColors(r->Xdisplay, XCMAP, &(xcol[1]), 1);
2139 # else
2140 xcol[0].pixel = WhitePixel(r->Xdisplay, XSCREEN);
2141 XQueryColors(r->Xdisplay, XCMAP, xcol, 2);
2142 # endif
2143
2144 /* bottomShadowColor */
2145 xcol[2].red = xcol[1].red / 2;
2146 xcol[2].green = xcol[1].green / 2;
2147 xcol[2].blue = xcol[1].blue / 2;
2148 if( !rxvt_alloc_color( r, &(xcol[2]), "Color_bottomShadow" ) )
2149 rxvt_copy_color( r, Color_bottomShadow, Color_Black );
2150
2151 else
2152 rxvt_set_color( r, Color_bottomShadow, &xcol[2] );
2153
2154
2155 /* topShadowColor */
2156 xcol[1].red = max((xcol[0].red / 5), xcol[1].red );
2157 xcol[1].green = max((xcol[0].green / 5), xcol[1].green);
2158 xcol[1].blue = max((xcol[0].blue / 5), xcol[1].blue );
2159 xcol[1].red = min(xcol[0].red, (xcol[1].red * 7) / 5);
2160 xcol[1].green = min(xcol[0].green, (xcol[1].green * 7) / 5);
2161 xcol[1].blue = min(xcol[0].blue, (xcol[1].blue * 7) / 5);
2162
2163 if( !rxvt_alloc_color(r, &(xcol[1]), "Color_topShadow") )
2164 rxvt_copy_color( r, Color_topShadow, Color_White );
2165 else
2166 rxvt_set_color( r, Color_topShadow, &xcol[1] );
2167
2168 }
2169 #endif /* KEEP_SCROLLCOLOR */
2170
2171
2172 #ifdef TEXT_SHADOW
2173 if (r->h->rs[Rs_textShadow])
2174 {
2175 XColor xcol;
2176 if( rxvt_parse_alloc_color( r, &xcol, r->h->rs[Rs_textShadow] ) )
2177 {
2178 r->TermWin.shadow = xcol.pixel;
2179 # ifdef XFT_SUPPORT
2180 rxvt_alloc_xft_color( r, &xcol, &(r->TermWin.xftshadow));
2181 # endif
2182 }
2183 else
2184 {
2185 r->TermWin.shadow = r->pixColorsFocus[Color_Black];
2186 # ifdef XFT_SUPPORT
2187 r->TermWin.xftshadow = r->xftColorsFocus[Color_Black];
2188 # endif
2189 }
2190 }
2191 #endif
2192 }
2193
2194
2195 /*----------------------------------------------------------------------*/
2196 /* color aliases, fg/bg bright-bold */
2197 /* INTPROTO */
2198 void
rxvt_color_aliases(rxvt_t * r,int idx)2199 rxvt_color_aliases( rxvt_t *r, int idx )
2200 {
2201 if (r->h->rs[Rs_color + idx] && isdigit((int) *(r->h->rs[Rs_color + idx])))
2202 {
2203 int i = atoi(r->h->rs[Rs_color + idx]);
2204
2205 if (i >= 8 && i <= 15) /* bright colors */
2206 {
2207 i -= 8;
2208 #ifndef NO_BRIGHTCOLOR
2209 r->h->rs[Rs_color + idx] = r->h->rs[Rs_color + minBrightCOLOR + i];
2210 return;
2211 #endif
2212 }
2213 if (i >= 0 && i <= 7) /* normal colors */
2214 r->h->rs[Rs_color + idx] = r->h->rs[Rs_color + minCOLOR +i];
2215 }
2216 }
2217
2218
2219 /* INTPROTO */
2220 void
rxvt_init_win_size(rxvt_t * r)2221 rxvt_init_win_size( rxvt_t *r )
2222 {
2223 int flags = 0; /* must initialize to 0!!! */
2224 short recalc_x = 0, recalc_y = 0,
2225 recalc_width = 1, recalc_height = 1;
2226 int x, y;
2227 unsigned int w, h;
2228
2229
2230 r->szHint.flags = PMinSize | PResizeInc | PBaseSize | PWinGravity;
2231 r->szHint.win_gravity = NorthWestGravity;
2232
2233 /* Set default terminal columns and rows */
2234 r->TermWin.ncol = 80;
2235 r->TermWin.nrow = 24;
2236 r->szHint.x = 0;
2237 r->szHint.y = 0;
2238
2239 #ifdef TRANSPARENT
2240 refreshRootBGVars( r );
2241 #endif
2242
2243 /* Get geometry in x, y, w, h */
2244 if (r->h->rs[Rs_geometry])
2245 flags = XParseGeometry(r->h->rs[Rs_geometry], &x, &y, &w, &h);
2246
2247 /* Calculate the terminal increment width and height */
2248 #ifndef NO_FRILLS
2249 if( ISSET_OPTION(r, Opt2_smoothResize))
2250 {
2251 r->szHint.width_inc = 1;
2252 r->szHint.height_inc = 1;
2253 }
2254 else
2255 #endif
2256 {
2257 r->szHint.width_inc = r->TermWin.fwidth;
2258 r->szHint.height_inc = r->TermWin.fheight;
2259 }
2260
2261 /* Calculate the base width and height */
2262 r->szHint.base_width = 2 * r->TermWin.int_bwidth;
2263 r->szHint.base_height = 2 * r->TermWin.int_bwidth;
2264 #ifdef HAVE_SCROLLBARS
2265 if (ISSET_OPTION(r, Opt_scrollBar))
2266 r->szHint.base_width += rxvt_scrollbar_rwidth (r);
2267 #endif
2268 #ifdef HAVE_MENUBAR
2269 if (ISSET_OPTION(r, Opt_showMenu))
2270 r->szHint.base_height += rxvt_menubar_rheight (r);
2271 #endif
2272 if (NOTSET_OPTION(r, Opt2_hideTabbar))
2273 r->szHint.base_height += rxvt_tabbar_rheight (r);
2274
2275 /* Set the terminal minimal width and height */
2276 r->szHint.min_width = r->szHint.base_width + r->TermWin.fwidth;
2277 r->szHint.min_height = r->szHint.base_height + r->TermWin.fheight;
2278
2279 /* Parse Geometry */
2280 if (flags & WidthValue)
2281 {
2282 r->TermWin.ncol = BOUND_POSITIVE_INT16(w);
2283 #ifndef NO_FRILLS
2284 if( ISSET_OPTION(r, Opt2_smoothResize) )
2285 {
2286 /* For smoothResize, w as a pixel width (if large enough) */
2287 if(r->TermWin.ncol > r->szHint.base_width + r->TermWin.fwidth)
2288 {
2289 r->szHint.width = r->TermWin.ncol;
2290 r->TermWin.ncol = (r->TermWin.ncol - r->szHint.base_width) /
2291 r->TermWin.fwidth;
2292 recalc_width = 0;
2293 }
2294 else r->TermWin.ncol = 1;
2295 }
2296 #endif
2297 r->szHint.flags |= USSize;
2298 }
2299 if (flags & HeightValue)
2300 {
2301 r->TermWin.nrow = BOUND_POSITIVE_INT16(h);
2302 #ifndef NO_FRILLS
2303 if(ISSET_OPTION(r, Opt2_smoothResize))
2304 {
2305 /* For smoothResize, w as a pixel height (if large enough) */
2306 if(r->TermWin.nrow > r->szHint.base_height + r->TermWin.fheight)
2307 {
2308 r->szHint.height = r->TermWin.nrow;
2309 r->TermWin.nrow =
2310 (r->TermWin.nrow - r->szHint.base_height) / r->TermWin.fheight;
2311 recalc_height = 0;
2312 }
2313 else r->TermWin.nrow = 1;
2314 }
2315 #endif
2316 r->szHint.flags |= USSize;
2317 }
2318 if (flags & XValue)
2319 {
2320 r->szHint.x = x;
2321 r->szHint.flags |= USPosition;
2322 if (flags & XNegative)
2323 {
2324 recalc_x = 1;
2325 r->szHint.win_gravity = NorthEastGravity;
2326 }
2327 }
2328 if (flags & YValue)
2329 {
2330 r->szHint.y = y;
2331 r->szHint.flags |= USPosition;
2332 if (flags & YNegative)
2333 {
2334 recalc_y = 1;
2335 if (r->szHint.win_gravity == NorthEastGravity)
2336 r->szHint.win_gravity = SouthEastGravity;
2337 else
2338 r->szHint.win_gravity = SouthWestGravity;
2339 }
2340 }
2341
2342 /* Set the terminal width and height */
2343 if( recalc_width)
2344 r->szHint.width = r->szHint.base_width + Width2Pixel (r->TermWin.ncol);
2345 if( recalc_height)
2346 r->szHint.height = r->szHint.base_height + Height2Pixel (r->TermWin.nrow);
2347
2348 /* Recalculate the starting position */
2349 if (recalc_x)
2350 r->szHint.x += (DisplayWidth(r->Xdisplay, XSCREEN)
2351 - r->szHint.width - 2 * r->TermWin.ext_bwidth);
2352 if (recalc_y)
2353 r->szHint.y += (DisplayHeight(r->Xdisplay, XSCREEN)
2354 - r->szHint.height - 2 * r->TermWin.ext_bwidth);
2355
2356 /* Set the terminal window starting position */
2357 r->h->window_vt_x = (ISSET_OPTION(r, Opt_scrollBar_right)) ?
2358 0 : r->szHint.base_width - 2*r->TermWin.int_bwidth;
2359 r->h->window_vt_y = r->szHint.base_height - 2*r->TermWin.int_bwidth;
2360 if (ISSET_OPTION(r, Opt2_bottomTabbar) && NOTSET_OPTION(r, Opt2_hideTabbar))
2361 r->h->window_vt_y -= rxvt_tabbar_rheight (r);
2362 }
2363
2364
2365 /*----------------------------------------------------------------------*/
2366 /*
2367 * Probe the modifier keymap to get the Meta (Alt) and Num_Lock settings
2368 * Use resource ``modifier'' to override the Meta modifier
2369 */
2370 /* INTPROTO */
2371 void
rxvt_get_ourmods(rxvt_t * r)2372 rxvt_get_ourmods( rxvt_t *r )
2373 {
2374 int i, j, k;
2375 int requestedmeta, realmeta, realalt;
2376 const char* cm;
2377 const char* rsmod;
2378 XModifierKeymap* map;
2379 KeyCode* kc;
2380 const unsigned int modmasks[] =
2381 {
2382 Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
2383 };
2384
2385
2386 requestedmeta = realmeta = realalt = 0;
2387
2388 rsmod = r->h->rs[Rs_modifier];
2389 if (rsmod &&
2390 STRCASECMP(rsmod, "mod1") >= 0 &&
2391 STRCASECMP(rsmod, "mod5") <= 0)
2392 requestedmeta = rsmod[3] - '0';
2393
2394 map = XGetModifierMapping(r->Xdisplay);
2395 kc = map->modifiermap;
2396 for (i = 1; i < 6; i++)
2397 {
2398 k = (i + 2) * map->max_keypermod; /* skip shift/lock/control */
2399 for (j = map->max_keypermod; j--; k++)
2400 {
2401 if (kc[k] == 0)
2402 break;
2403
2404 switch (XKeycodeToKeysym(r->Xdisplay, kc[k], 0))
2405 {
2406 case XK_Num_Lock:
2407 r->h->ModNumLockMask = modmasks[i - 1];
2408 /* FALLTHROUGH */
2409 default:
2410 continue; /* for(;;) */
2411 case XK_Meta_L:
2412 case XK_Meta_R:
2413 cm = "meta";
2414 realmeta = i;
2415 break;
2416 case XK_Alt_L:
2417 case XK_Alt_R:
2418 cm = "alt";
2419 realalt = i;
2420 break;
2421 case XK_Super_L:
2422 case XK_Super_R:
2423 cm = "super";
2424 break;
2425 case XK_Hyper_L:
2426 case XK_Hyper_R:
2427 cm = "hyper";
2428 break;
2429 }
2430
2431 if (rsmod && STRNCASECMP(rsmod, cm, STRLEN(cm)) == 0)
2432 requestedmeta = i;
2433 }
2434 }
2435 XFreeModifiermap(map);
2436
2437 i = (requestedmeta ? requestedmeta : (
2438 realmeta ? realmeta : (
2439 realalt ? realalt : 0)));
2440
2441 if (i)
2442 r->h->ModMetaMask = modmasks[i - 1];
2443 }
2444
2445
2446
2447 /* EXTPROTO */
2448 char**
rxvt_string_to_argv(const char * string,int * argc)2449 rxvt_string_to_argv( const char *string, int *argc )
2450 {
2451 int i = 0;
2452 char** pret;
2453 const char* pcur;
2454 #ifdef INTERNAL_ARGV_SPLIT
2455 const char* pbeg;
2456 #endif
2457
2458 *argc = 0;
2459 if( IS_NULL(string) || *string == '\0' )
2460 {
2461 *argc = 0;
2462 return NULL;
2463 }
2464
2465 #define MAX_ARGV (1024)
2466 /* Up to 64 argv.
2467 *
2468 * 2006-02-23 gi1242: Use calloc instead of malloc. Thus when freeing pret,
2469 * we can safely free all elements till we encounter a NULL pointer.
2470 */
2471 pret = (char**) rxvt_calloc (MAX_ARGV, sizeof (char*));
2472
2473 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "fetch command argv for the tab\n"));
2474 #ifdef INTERNAL_ARGV_SPLIT
2475 /*{{{*/
2476 /*
2477 * 2006-02-23 gi1242: Remember to leave space for a NULL terminated pointer
2478 * at the end
2479 */
2480 pbeg = pcur = string;
2481 for (i = 0; i < MAX_ARGV-2; i ++)
2482 {
2483 int dq = 0; /* double quote */
2484 int sq = 0; /* single quote */
2485 /* set default argument to NULL */
2486 SET_NULL(pret[i]);
2487
2488 /* skip any spaces and non-printable */
2489 while (*pcur &&
2490 (isspace ((int) *pcur) || !isprint ((int) *pcur)))
2491 pcur ++;
2492 /* stop if reach end of string */
2493 if (!*pcur)
2494 break;
2495
2496 /* beginning of the token */
2497 if (isalnum ((int) *pcur) || ispunct ((int) *pcur))
2498 {
2499 if ('\"' == *pcur)
2500 {
2501 /* beginning of double quote */
2502 dq = 1; pbeg = pcur + 1; pcur ++;
2503 }
2504 else if ('\'' == *pcur)
2505 {
2506 /* beginning of single quote */
2507 sq = 1; pbeg = pcur + 1; pcur ++;
2508 }
2509 else /* normal characters */
2510 pbeg = pcur;
2511 }
2512 #ifdef DEBUG
2513 else /* shouldn't happen */
2514 assert (0);
2515 #endif
2516
2517 /* move forward one character */
2518 pcur ++;
2519
2520 /* now fetch the new token */
2521 while(
2522 *pcur && /* not end of string */
2523 (
2524 (dq && *pcur != '\"') || /* not end of double quote */
2525 (sq && *pcur != '\'') || /* not end of single quote */
2526 (!dq && !sq && !isspace ((int) *pcur))
2527 )
2528 )
2529 {
2530 pcur ++;
2531 }
2532
2533 if (!*pcur && /* end of string */
2534 (dq || sq)) /* no match of quote is found */
2535 goto NotMatch;
2536
2537 if (!*pcur) /* end of string */
2538 {
2539 pret[i] = STRDUP (pbeg);
2540 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, " argv[%d] = %s\n", i, pret[i]));
2541 break; /* ready to return */
2542 }
2543
2544 if (
2545 (dq && *pcur == '\"') /* end of double quote */
2546 || (sq && *pcur == '\'') /* end of single quote */
2547 || (!dq && !sq && isspace ((int) *pcur)) /* space */
2548 )
2549 {
2550 int len = sizeof (char) * (pcur - pbeg) + 1;
2551
2552 assert (len > 0); /* possible integer overflow? */
2553 pret[i] = (char*) rxvt_malloc (len * sizeof(char));
2554 MEMCPY (pret[i], pbeg, len-1);
2555 pret[i][len-1] = (char) 0;
2556 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, " argv[%d] = %s\n", i, pret[i]));
2557
2558 /* forward to next character */
2559 pcur ++;
2560
2561 /* fetch next token */
2562 continue;
2563 }
2564
2565 /* shouldn't get here */
2566 assert (0);
2567 }
2568 /*}}}*/
2569 #else /* !INTERNAL_ARGV_SPLIT */
2570
2571 /*
2572 * Pass strings beginning with "!" but not "!!" to /bin/sh -c
2573 */
2574 if( *string == '!' && *(++string) != '!' )
2575 {
2576 /* Pass command to the shell for word splitting */
2577 pret[i++] = STRDUP( "/bin/sh" );
2578 pret[i++] = STRDUP( "-c" );
2579 pret[i++] = STRDUP( string );
2580 }
2581
2582 else
2583 {
2584 /*
2585 * Split command into words at spaces. White spaces can be quoted with
2586 * a backslash. However we don't processes chains of "\\" which don't
2587 * end in a space or tab. That is "\\a" expands to "\\a" however "\\ "
2588 * expands to "\ ", and "\ " expands to a " " which does not split
2589 * words.
2590 */
2591 pcur = string;
2592 for( ; i < MAX_ARGV && *pcur; i++ )
2593 {
2594 const int max_argv_len = 1024;
2595 char argval[max_argv_len];
2596 int j = 0;
2597
2598 /* Skip leading spaces */
2599 while( *pcur == ' ' || *pcur == '\t' ) pcur++;
2600
2601 while(
2602 *pcur && *pcur != ' ' && *pcur != '\t' &&
2603 j < max_argv_len - 1
2604 )
2605 {
2606 if( *pcur == '\\' )
2607 {
2608 const char *s = pcur + 1;
2609
2610 /* Count backslashes */
2611 while( *s == '\\' )
2612 s++;
2613
2614 if( *s == ' ' || *s == '\t' )
2615 {
2616 int nbslashs = s - pcur;
2617 int nbytes = min( nbslashs / 2, max_argv_len - j - 1);
2618
2619 /* Halve # backslashes */
2620 MEMSET( &argval[j], '\\', nbytes );
2621 pcur = s;
2622 j += nbytes;
2623
2624 if( nbslashs % 2 == 0 )
2625 break; /* Split word here */
2626 }
2627
2628 else
2629 {
2630 /* Copy backslashes over verbatim */
2631 int nbytes = min( s - pcur, max_argv_len -j -1 );
2632
2633 MEMCPY( &argval[j], pcur, nbytes );
2634 j += nbytes;
2635 pcur = s;
2636 }
2637 } /* if( pcur = '\\' ) */
2638
2639 argval[j++] = *pcur++;
2640 } /* while( *pcur ... ) */
2641
2642 if( j )
2643 {
2644 argval[j] = '\0';
2645 pret[i] = STRDUP( argval );
2646 }
2647 else
2648 break;
2649 }
2650 } /* else [ if( *string != '!' ) ] */
2651 #endif /* !INTERNAL_ARGV_SPLIT */
2652
2653 #undef MAX_ARGV
2654 /* set the end of argv */
2655 if (pret[i])
2656 {
2657 *argc = i+1;
2658 SET_NULL(pret[i+1]);
2659 }
2660 else if (i) /* non-empty argv */
2661 {
2662 *argc = i;
2663 }
2664 else /* empty argv */
2665 {
2666 #if 0
2667 /* 2006-02-23 gi1242: Also need to free the char* pointers in pret? */
2668 rxvt_free (pret);
2669 return NULL;
2670 #endif
2671 goto NotMatch;
2672 }
2673
2674 /* 2006-02-23 gi1242: Can now reduce the size of pret. */
2675 pret = (char **) rxvt_realloc( pret, (*argc + 1) * sizeof(char*) );
2676 return pret;
2677
2678 NotMatch:
2679 *argc = 0;
2680 {
2681 char **s;
2682 for( s = pret; NOT_NULL(*s); s++) rxvt_free(*s);
2683 }
2684
2685 rxvt_free (pret);
2686 return NULL;
2687 }
2688
2689
2690 /*
2691 * Sets up the fg/bg correctly in pixColorsFocus/unfocus, the fg/bg of
2692 * TermWin.gc, and the fg/bg of the window (if active).
2693 */
2694 /* EXTPROTO */
2695 int
rxvt_set_vt_colors(rxvt_t * r,int page)2696 rxvt_set_vt_colors( rxvt_t *r, int page )
2697 {
2698 int changed = 0;
2699 int useFocusColors;
2700 unsigned long *pix_colors;
2701
2702 rxvt_dbgmsg(( DBG_DEBUG, DBG_INIT, "%s(r, page=%d). ", __func__, page ));
2703
2704 useFocusColors = ( r->TermWin.focus || !r->TermWin.fade );
2705 pix_colors = (useFocusColors ? r->pixColorsFocus : r->pixColorsUnfocus);
2706 if( r->pixColors != pix_colors )
2707 {
2708 changed = 1;
2709 r->pixColors = pix_colors;
2710 }
2711
2712 #ifdef XFT_SUPPORT
2713 if( ISSET_OPTION( r, Opt_xft ) )
2714 r->xftColors = useFocusColors ? r->xftColorsFocus : r->xftColorsUnfocus;
2715 #endif
2716
2717 if( rxvt_set_fgbg_colors( r, page ) )
2718 changed = 1;
2719
2720 if( changed )
2721 {
2722 /*
2723 * Set foreground/background color for GC. This is necessary. Since all
2724 * VTs share the same GC, if we do not set the color here, color from
2725 * other VTs will be used to draw the following text till there is a
2726 * color change.
2727 */
2728 XSetForeground( r->Xdisplay, r->TermWin.gc, r->pixColors[Color_fg] );
2729 XSetBackground( r->Xdisplay, r->TermWin.gc, r->pixColors[Color_bg] );
2730
2731 if( IS_WIN( PVTS(r, page)->vt ) )
2732 # ifdef TRANSPARENT
2733 if (NOTSET_OPTION(r, Opt_transparent))
2734 # endif /* TRANSPARENT */
2735 #ifdef BACKGROUND_IMAGE
2736 if (NOT_PIXMAP(PVTS(r, page)->pixmap))
2737 #endif /* BACKGROUND_IMAGE */
2738 XSetWindowBackground(r->Xdisplay, PVTS(r, page)->vt,
2739 r->pixColors[Color_bg]);
2740 }
2741
2742 rxvt_dbgmsg(( DBG_DEBUG, DBG_INIT, "Returning %d\n", changed ));
2743 return changed;
2744 }
2745
2746
2747 /* INTPROTO */
2748 termenv_t
rxvt_get_termenv(const char * env)2749 rxvt_get_termenv( const char *env )
2750 {
2751 if (IS_NULL(env))
2752 return (TERMENV_XTERM);
2753 else if (0 == STRCASECMP (env, "xterm"))
2754 return (TERMENV_XTERM);
2755 else if (0 == STRCASECMP (env, "rxvt"))
2756 return (TERMENV_RXVT);
2757 else if (0 == STRCASECMP (env, "vt102"))
2758 return (TERMENV_VT102);
2759 else if (0 == STRCASECMP (env, "vt100"))
2760 return (TERMENV_VT100);
2761 else if (0 == STRCASECMP (env, "ansi"))
2762 return (TERMENV_ANSI);
2763 else if (0 == STRCASECMP (env, "dumb"))
2764 return (TERMENV_DUMB);
2765 else
2766 return (TERMENV_XTERM);
2767 }
2768
2769
2770 /* INTPROTO */
2771 void
rxvt_init_vts(rxvt_t * r,int page,int profile)2772 rxvt_init_vts( rxvt_t *r, int page, int profile )
2773 {
2774 #ifdef TTY_GID_SUPPORT
2775 struct group* gr = getgrnam( "tty" );
2776 #endif
2777 register int i;
2778
2779
2780 assert( page < MAX_PAGES );
2781
2782 /* look for an unused term_t structure */
2783 for( i = 0; i < MAX_PAGES; i ++ )
2784 if( -1 == r->vterm[i].vts_idx )
2785 break;
2786 assert( i != MAX_PAGES );
2787 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "Find vterm[%d] for pointer vts[%d]\n", i, page));
2788
2789 /* clear the term_t structure */
2790 r->vts[page] = &(r->vterm[i]);
2791 MEMSET( r->vts[page], 0, sizeof( r->vterm[0] ) );
2792
2793 /* set vts_idx for the vterm */
2794 PVTS(r, page)->vts_idx = i;
2795
2796 /* Set the profile number */
2797 PVTS(r, page)->profileNum = profile;
2798
2799 /* Save the "static" number of this tab */
2800 PVTS(r, page)->globalTabNum = r->ntabs++;
2801
2802 #ifdef TTY_GID_SUPPORT
2803 /* change group ownership of tty to "tty" */
2804 if (gr)
2805 {
2806 PVTS(r, page)->ttymode = S_IRUSR | S_IWUSR | S_IWGRP;
2807 }
2808 else
2809 #endif /* TTY_GID_SUPPORT */
2810 {
2811 PVTS(r, page)->ttymode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
2812 }
2813
2814 /* Initialize term_t (vts) structure */
2815 PVTS( r, page )->saveLines = r->profile[profile].saveLines;
2816
2817 /* will be set in rxvt_create_termwin */
2818 UNSET_WIN(PVTS(r, page)->vt);
2819
2820 #ifdef XFT_SUPPORT
2821 SET_NULL(PVTS(r, page)->xftvt);
2822 #endif
2823 SET_NULL(PVTS(r, page)->tab_title);
2824
2825 /*
2826 * Set the tab title format, and window title format. getProfileOption
2827 * returns a static string, so duplicate it here
2828 */
2829 {
2830 const char *stf = getProfileOption( r, profile, Rs_titleFormat );
2831 PVTS(r, page)->title_format = NOT_NULL(stf) ? STRDUP(stf) : NULL;
2832 }
2833
2834 {
2835 const char *wtf = getProfileOption( r, profile, Rs_winTitleFormat );
2836 PVTS(r, page)->winTitleFormat = NOT_NULL(wtf) ? STRDUP(wtf) : NULL;
2837 }
2838
2839 #ifdef BACKGROUND_IMAGE
2840 UNSET_PIXMAP(PVTS(r, page)->pixmap);
2841 UNSET_PIXMAP(PVTS(r, page)->bg.pixmap);
2842 PVTS(r, page)->bg.x = PVTS(r, page)->bg.y = 50;
2843 #endif
2844 PVTS(r, page)->cmd_pid = -1;
2845 PVTS(r, page)->cmd_fd = PVTS(r, page)->tty_fd = -1;
2846 #ifdef UTMP_SUPPORT
2847 PVTS(r, page)->next_utmp_action = SAVE;
2848 #endif
2849 #ifndef NO_SETOWNER_TTYDEV
2850 PVTS(r, page)->next_tty_action = SAVE;
2851 #endif
2852
2853 PVTS(r, page)->holdOption = r->profile[profile].holdOption;
2854
2855 PVTS(r, page)->status = 0;
2856 PVTS(r, page)->hold = 0; /* clear hold flag */
2857 PVTS(r, page)->dead = 0; /* clear dead flag */
2858 PVTS(r, page)->highlight = 0; /* clear highlight flag */
2859
2860 /* Get term_env type */
2861 PVTS(r, page)->termenv = rxvt_get_termenv (
2862 r->h->rs[Rs_term_name] ? r->h->rs[Rs_term_name] : TERMENV);
2863
2864 /* Initialize PrivateModes and SavedModes */
2865 PVTS(r, page)->PrivateModes = PVTS(r, page)->SavedModes =
2866 PrivMode_Default;
2867 if (ISSET_OPTION(r, Opt_scrollTtyOutputInhibit))
2868 SET_PMODE(r, page, PrivMode_TtyOutputInh);
2869 if (ISSET_OPTION(r, Opt_scrollTtyKeypress))
2870 SET_PMODE(r, page, PrivMode_Keypress);
2871 if( r->h->skip_pages > 1 /* jump scroll is unset */ )
2872 SET_PMODE(r, page, PrivMode_smoothScroll);
2873 #ifndef NO_BACKSPACE_KEY
2874 if (STRCMP(r->h->key_backspace, "DEC") == 0)
2875 SET_PMODE(r, page, PrivMode_HaveBackSpace);
2876 #endif
2877 #ifdef HAVE_SCROLLBARS
2878 if (rxvt_scrollbar_visible(r))
2879 {
2880 SET_PMODE(r, page, PrivMode_scrollBar);
2881 SET_SMODE(r, page, PrivMode_scrollBar);
2882 }
2883 #endif
2884 #ifdef HAVE_MENUBAR
2885 if (rxvt_menubar_visible(r))
2886 {
2887 SET_PMODE(r, page, PrivMode_menuBar);
2888 SET_SMODE(r, page, PrivMode_menuBar);
2889 }
2890 #endif
2891
2892 /* Now set VT fg/bg color */
2893 PVTS(r, page)->p_fg = VTFG(r, profile);
2894 PVTS(r, page)->p_bg = VTBG(r, profile);
2895
2896 if( r->TermWin.fade )
2897 {
2898 PVTS(r, page)->p_fgfade = VTFG_FADE(r, profile);
2899 PVTS(r, page)->p_bgfade = VTBG_FADE(r, profile);
2900 }
2901
2902 #ifdef XFT_SUPPORT
2903 if( ISSET_OPTION( r, Opt_xft ) )
2904 {
2905 PVTS(r, page)->p_xftfg = VTXFTFG(r, profile);
2906 PVTS(r, page)->p_xftbg = VTXFTBG(r, profile);
2907
2908 if( r->TermWin.fade )
2909 {
2910 PVTS(r, page)->p_xftfgfade = VTXFTFG_FADE(r, profile);
2911 PVTS(r, page)->p_xftbgfade = VTXFTBG_FADE(r, profile);
2912 }
2913 }
2914 #endif
2915
2916 /* Initialize input buffer */
2917 PVTS(r, page)->cmdbuf_ptr = PVTS(r, page)->cmdbuf_endp
2918 = PVTS(r, page)->cmdbuf_base;
2919
2920 /* Initialize write out buffer */
2921 SET_NULL(PVTS(r, page)->v_buffer);
2922 SET_NULL(PVTS(r, page)->v_bufstr);
2923 SET_NULL(PVTS(r, page)->v_bufptr);
2924 SET_NULL(PVTS(r, page)->v_bufend);
2925
2926 /* Set screen structure initialization flag */
2927 PVTS(r, page)->init_screen = 0;
2928
2929 /* Request a refresh */
2930 PVTS(r, page)->want_refresh = 1;
2931 }
2932
2933
2934 /*----------------------------------------------------------------------*/
2935 /* rxvt_destroy_termwin() - destroy a terminal window */
2936 /* EXTPROTO */
2937 void
rxvt_destroy_termwin(rxvt_t * r,int page)2938 rxvt_destroy_termwin( rxvt_t *r, int page )
2939 {
2940 assert (page < MAX_PAGES);
2941 assert (PVTS(r, page)->tab_title);
2942
2943 rxvt_free (PVTS(r, page)->tab_title);
2944 SET_NULL(PVTS(r, page)->tab_title);
2945
2946 rxvt_free( PVTS(r, page)->title_format );
2947 SET_NULL( PVTS(r, page)->title_format );
2948
2949 #ifdef XFT_SUPPORT
2950 if (ISSET_OPTION(r, Opt_xft))
2951 {
2952 if (PVTS(r, page)->xftvt)
2953 XftDrawDestroy (PVTS(r, page)->xftvt);
2954 SET_NULL(PVTS(r, page)->xftvt);
2955 }
2956 #endif
2957 assert (IS_WIN(PVTS(r, page)->vt));
2958 XDestroyWindow (r->Xdisplay, PVTS(r, page)->vt);
2959 UNSET_WIN(PVTS(r, page)->vt);
2960
2961 #ifdef BACKGROUND_IMAGE
2962 if (IS_PIXMAP(PVTS(r, page)->pixmap))
2963 {
2964 XFreePixmap (r->Xdisplay, PVTS(r, page)->pixmap);
2965 UNSET_PIXMAP(PVTS(r, page)->pixmap);
2966 }
2967 if (IS_PIXMAP(PVTS(r, page)->bg.pixmap))
2968 {
2969 XFreePixmap (r->Xdisplay, PVTS(r, page)->bg.pixmap);
2970 UNSET_PIXMAP(PVTS(r, page)->bg.pixmap);
2971 }
2972 #endif
2973
2974 /* Set vterm index to -1, so that we know it's unused */
2975 PVTS(r, page)->vts_idx = -1;
2976 }
2977
2978
2979
2980 /* rxvt_create_termwin() - create a terminal window */
2981 /* EXTPROTO */
2982 void
rxvt_create_termwin(rxvt_t * r,int page,int profile,const char TAINTED * title)2983 rxvt_create_termwin( rxvt_t *r, int page, int profile,
2984 const char TAINTED *title )
2985 {
2986 long vt_emask;
2987
2988
2989 assert( page < MAX_PAGES );
2990
2991 rxvt_init_vts( r, page, profile );
2992
2993 /*
2994 * Set the tab title
2995 */
2996 if (IS_NULL(title))
2997 title = DEFAULT_TAB_TITLE;
2998 PVTS(r, page)->tab_title = (char UNTAINTED *) STRNDUP( title, MAX_TAB_TXT );
2999
3000 #ifdef HAVE_PUTENV
3001 /* Set environment variable of tab title */
3002 sprintf (r->h->env_tabtitle, TABTITLEENV "%s", PVTS(r, page)->tab_title);
3003 putenv (r->h->env_tabtitle);
3004 #endif
3005
3006 PVTS(r, page)->tab_width = rxvt_tab_width (r, PVTS(r, page)->tab_title);
3007
3008 /*
3009 * Now switch fg/bg colors before creating VT because this will use the
3010 * fg/bg colors
3011 */
3012 rxvt_set_vt_colors( r, page );
3013
3014 /* create the terminal window */
3015 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "Create VT %d (%dx%d+%dx%d) fg=%06lx, bg=%06lx\n", page, r->h->window_vt_x, r->h->window_vt_y, VT_WIDTH(r), VT_HEIGHT(r), r->pixColors[Color_fg], r->pixColors[Color_bg]));
3016
3017 PVTS(r, page)->vt = XCreateSimpleWindow (r->Xdisplay, r->TermWin.parent,
3018 r->h->window_vt_x, r->h->window_vt_y,
3019 VT_WIDTH(r), VT_HEIGHT(r),
3020 0,
3021 r->pixColors[Color_fg],
3022 r->pixColors[Color_bg]);
3023 assert (IS_WIN(PVTS(r, page)->vt));
3024 #ifdef XFT_SUPPORT
3025 if (ISSET_OPTION(r, Opt_xft))
3026 {
3027 PVTS(r, page)->xftvt = XftDrawCreate (r->Xdisplay,
3028 PVTS(r, page)->vt, XVISUAL, XCMAP);
3029 assert (NOT_NULL(PVTS(r, page)->xftvt));
3030 }
3031 #endif
3032
3033
3034 /* define cursor for the terminal window */
3035 rxvt_pointer_unblank(r, page);
3036
3037 /* define event mask fo the terminal window */
3038 vt_emask = (ExposureMask | ButtonPressMask | ButtonReleaseMask
3039 | PropertyChangeMask);
3040 #ifdef POINTER_BLANK
3041 if (ISSET_OPTION(r, Opt_pointerBlank))
3042 vt_emask |= PointerMotionMask;
3043 else
3044 #endif
3045 vt_emask |= (Button1MotionMask | Button3MotionMask);
3046 XSelectInput(r->Xdisplay, PVTS(r, page)->vt, vt_emask);
3047
3048 #ifdef TRANSPARENT
3049 /* Set transparent background */
3050 if (ISSET_OPTION(r, Opt_transparent))
3051 {
3052 XSetWindowBackgroundPixmap (r->Xdisplay, PVTS(r, page)->vt,
3053 ParentRelative);
3054 }
3055 #endif
3056
3057 /*
3058 * Load the background image for terminal window when not transparent
3059 */
3060 #ifdef BACKGROUND_IMAGE
3061 # ifdef TRANSPARENT
3062 if( NOTSET_OPTION(r, Opt_transparent) )
3063 # endif
3064 {
3065 const char *pf = getProfileOption( r, profile, Rs_backgroundPixmap );
3066 if (NOT_NULL(pf))
3067 {
3068 /* Load pixmap for each individual tab */
3069 const char *p = pf;
3070
3071 if (NOT_NULL(p = STRCHR(p, ';')))
3072 {
3073 p++;
3074 rxvt_scale_pixmap(r, page, p);
3075 }
3076 rxvt_load_bg_pixmap(r, page, pf);
3077 /* rxvt_scr_touch(r, page, True); */
3078 }
3079 } /* if( NOTSET_OPTION(r, Opt_transparent) ) */
3080 #endif
3081
3082 XMapWindow (r->Xdisplay, PVTS(r, page)->vt);
3083 }
3084
3085
3086 /*
3087 * Return the value of an option with profile number "profile". This function
3088 * should only be called for profile options.
3089 *
3090 * The string returned is one of r->h->rs[], so should not be freed.
3091 */
3092 /* EXTPROTO */
3093 const char *
getProfileOption(rxvt_t * r,int profile,int resource)3094 getProfileOption( rxvt_t *r, int profile, int resource )
3095 {
3096 assert( profile >= 0 || profile < MAX_PROFILES );
3097
3098 /*
3099 * Profile 0 is default, so if the profile option is unset, fall back to
3100 * profile 0.
3101 */
3102 return NOT_NULL(r->h->rs[resource + profile]) ?
3103 r->h->rs[resource + profile] : r->h->rs[resource];
3104 }
3105
3106 /* INTPROTO */
3107 void
rxvt_set_borderless(rxvt_t * r)3108 rxvt_set_borderless( rxvt_t *r )
3109 {
3110 Atom prop;
3111 CARD32 hints; /* KDE/GNOME hints */
3112 MWMHints mwmhints; /* Motif hints */
3113
3114 hints = (CARD32) 0;
3115 mwmhints.flags = MWM_HINTS_DECORATIONS;
3116 mwmhints.decorations = 0;
3117
3118 /* Motif compatible WM */
3119 prop = XInternAtom (r->Xdisplay, "_MOTIF_WM_HINTS", True);
3120 if (IS_ATOM(prop))
3121 XChangeProperty (r->Xdisplay, r->TermWin.parent, prop, prop,
3122 32, PropModeReplace, (unsigned char*) &mwmhints,
3123 PROP_MWM_HINTS_ELEMENTS);
3124
3125 /* GNOME compatible WM */
3126 prop = XInternAtom (r->Xdisplay, "_WIN_HINTS", True);
3127 if (IS_ATOM(prop))
3128 XChangeProperty (r->Xdisplay, r->TermWin.parent, prop, prop,
3129 32, PropModeReplace, (unsigned char*) &hints, 1);
3130
3131 /* KDE compatible WM */
3132 prop = XInternAtom (r->Xdisplay, "KWM_WIN_DECORATION", True);
3133 if (IS_ATOM(prop))
3134 XChangeProperty (r->Xdisplay, r->TermWin.parent, prop, prop,
3135 32, PropModeReplace, (unsigned char*) &hints, 1);
3136 }
3137
3138 /*
3139 * Send a message to an EWMH compatible window manager.
3140 */
3141 /* EXTPROTO */
3142 Status
ewmh_message(Display * dpy,Window root_win,Window client_win,Atom msgAtom,long d0,long d1,long d2,long d3,long d4)3143 ewmh_message( Display *dpy, Window root_win, Window client_win,
3144 Atom msgAtom, long d0, long d1, long d2, long d3, long d4)
3145 {
3146
3147 XEvent event;
3148
3149 if (NOT_ATOM(msgAtom))
3150 return 1;
3151
3152 event.xclient.type = ClientMessage;
3153 event.xclient.serial = 0;
3154 event.xclient.send_event = True;
3155 event.xclient.message_type = msgAtom;
3156 event.xclient.window = client_win;
3157 event.xclient.format = 32;
3158
3159 event.xclient.data.l[0] = d0;
3160 event.xclient.data.l[1] = d1;
3161 event.xclient.data.l[2] = d2;
3162 event.xclient.data.l[3] = d3;
3163 event.xclient.data.l[4] = d4;
3164
3165 return XSendEvent( dpy, root_win, False,
3166 SubstructureRedirectMask | SubstructureNotifyMask,
3167 &event);
3168 }
3169
3170
3171 /* INTPROTO */
3172 void
rxvt_set_desktop(rxvt_t * r,CARD32 desktop)3173 rxvt_set_desktop( rxvt_t* r, CARD32 desktop )
3174 {
3175 /* GNOME compatible WM */
3176 if (desktop >= 0 && desktop <= 64 &&
3177 IS_ATOM(r->h->xa[XA_WIN_WORKSPACE]))
3178 XChangeProperty(r->Xdisplay, r->TermWin.parent,
3179 r->h->xa[XA_WIN_WORKSPACE], XA_CARDINAL, 32,
3180 PropModeReplace, (unsigned char*) &desktop, 1L);
3181
3182 /* WindowMaker/FreeDesktop.org compatible WM */
3183 if (desktop >= 0 && desktop <= 64 &&
3184 IS_ATOM(r->h->xa[XA_NET_WM_DESKTOP]))
3185 XChangeProperty(r->Xdisplay, r->TermWin.parent,
3186 r->h->xa[XA_NET_WM_DESKTOP], XA_CARDINAL, 32,
3187 PropModeReplace, (unsigned char*) &desktop, 1L);
3188 }
3189
3190
3191 /* EXTPROTO */
3192 CARD32
rxvt_get_desktop(rxvt_t * r)3193 rxvt_get_desktop( rxvt_t* r )
3194 {
3195 Atom ret_type;
3196 int format;
3197 unsigned long nitems;
3198 unsigned long bytes_after;
3199 unsigned char *prop;
3200 CARD32 desktop;
3201
3202 if (NOT_ATOM(r->h->xa[XA_NET_WM_DESKTOP]))
3203 return 0;
3204
3205 if(
3206 XGetWindowProperty( r->Xdisplay, r->TermWin.parent,
3207 r->h->xa[XA_NET_WM_DESKTOP], 0L, LONG_MAX, False, XA_CARDINAL,
3208 &ret_type, &format, &nitems, &bytes_after, &prop)
3209 != Success
3210 )
3211 return 0;
3212
3213 if( ret_type == XA_CARDINAL && format == 32 )
3214 {
3215 desktop = ((CARD32*) prop)[0];
3216 if (desktop < 0 || desktop > 64)
3217 desktop = 0;
3218 }
3219 else
3220 desktop = 0;
3221
3222 XFree( prop);
3223
3224 rxvt_dbgmsg(( DBG_DEBUG, DBG_INIT, "Desktop: %lu\n", desktop ));
3225 return desktop;
3226 }
3227
3228
3229 /*----------------------------------------------------------------------*/
3230 /* rxvt_create_show_windows() - Open and map the window */
3231 /* EXTPROTO */
3232 void
rxvt_create_show_windows(rxvt_t * r,int argc,const char * const * argv)3233 rxvt_create_show_windows( rxvt_t *r, int argc, const char *const *argv )
3234 {
3235 XClassHint class_hint;
3236 XWMHints wm_hint;
3237 XTextProperty win_prop;
3238 XTextProperty icon_prop;
3239 XGCValues gcvalue;
3240 unsigned long gcmask;
3241 #ifndef NO_FRILLS
3242 CARD32 pid = (CARD32) getpid ();
3243 #endif
3244 #ifdef TRANSPARENT
3245 register int i;
3246 #endif
3247 #ifdef POINTER_BLANK
3248 static const XColor blackcolour = { 0, 0, 0, 0, 0, 0 };
3249 #endif
3250
3251 Window parent; /* WinID to use for parent window */
3252
3253 #ifdef PREFER_24BIT
3254 XSetWindowAttributes attributes;
3255 XWindowAttributes gattr;
3256
3257
3258 XCMAP = DefaultColormap(r->Xdisplay, XSCREEN);
3259 XVISUAL = DefaultVisual(r->Xdisplay, XSCREEN);
3260
3261 if (ISSET_OPTION(r, Opt_transparent))
3262 {
3263 XGetWindowAttributes(r->Xdisplay,
3264 RootWindow(r->Xdisplay, XSCREEN), &gattr);
3265 XDEPTH = gattr.depth;
3266 }
3267 else
3268 {
3269 XDEPTH = DefaultDepth(r->Xdisplay, XSCREEN);
3270 /*
3271 * If depth is not 24, look for a 24bit visual.
3272 */
3273 if (XDEPTH != 24)
3274 {
3275 XVisualInfo vinfo;
3276
3277 if (XMatchVisualInfo(r->Xdisplay, XSCREEN, 24, TrueColor, &vinfo))
3278 {
3279 XDEPTH = 24;
3280 XVISUAL = vinfo.visual;
3281 XCMAP = XCreateColormap(r->Xdisplay,
3282 RootWindow(r->Xdisplay, XSCREEN),
3283 XVISUAL, AllocNone);
3284 }
3285 }
3286 }
3287 #endif
3288
3289
3290 /* grab colors before netscape does */
3291 rxvt_init_colors (r);
3292
3293 /*
3294 * Initialize fonts.
3295 * . Always load X11 fonts since pointer_blank uses it
3296 * . Load XFT font after X11 fonts. If succeeds, XFT font will
3297 * update font width/height and be used by default
3298 *
3299 * 03/09/2006 gi1242: TODO Don't load the X11 font unless absolutely
3300 * necessary. It will speed up startup (minimaly), and reduce resource
3301 * usage (minimaly).
3302 */
3303 #ifdef XFT_SUPPORT
3304 if (ISSET_OPTION(r, Opt_xft))
3305 {
3306 if (!rxvt_init_font_xft (r))
3307 {
3308 rxvt_msg (DBG_INFO, DBG_INIT,
3309 "Failed to load FreeType font, fallback to X11 font\n");
3310 /* disable xft */
3311 UNSET_OPTION(r, Opt_xft);
3312 }
3313 else
3314 xftInitACS (r->Xdisplay, XROOT, XDEPTH);
3315 }
3316 #endif
3317 /* init fallback X11 font */
3318 rxvt_init_font_x11( r );
3319
3320
3321 /*
3322 * must initialize scrollbar before initialize window size and
3323 * create windows.
3324 */
3325 #ifdef HAVE_SCROLLBARS
3326 rxvt_scrollbar_init (r);
3327 #endif
3328 rxvt_init_win_size (r);
3329
3330 /*
3331 * Use window specified by -into option as the parent window.
3332 */
3333 if( r->h->rs[Rs_container_window] )
3334 {
3335 XWindowAttributes attrs;
3336
3337 r->h->allowedxerror = 1; /* Enable Xerror reporting */
3338 r->h->xerror_return = Success;
3339
3340 parent = strtoul( r->h->rs[Rs_container_window], NULL, 0 );
3341
3342 XGetWindowAttributes( r->Xdisplay, parent, &attrs );
3343
3344 /* Check if we have valid attributes */
3345 if( r->h->xerror_return != Success || attrs.class == InputOnly )
3346 {
3347 rxvt_msg (DBG_ERROR, DBG_INIT, "Unable to embed into Win 0x%lx", parent );
3348 parent = XROOT;
3349 }
3350
3351 r->h->allowedxerror = 0; /* Disable Xerror reporting */
3352 }
3353 else
3354 parent = XROOT;
3355
3356 /*
3357 * parent window - reverse video so we can see placement errors sub-window
3358 * placement & size in rxvt_resize_subwindows()
3359 */
3360
3361 #ifdef PREFER_24BIT
3362 attributes.background_pixel = r->pixColorsFocus[Color_bg];
3363 attributes.border_pixel = r->pixColorsFocus[Color_border];
3364 attributes.colormap = XCMAP;
3365 r->TermWin.parent = XCreateWindow(r->Xdisplay, parent,
3366 r->szHint.x, r->szHint.y,
3367 r->szHint.width, r->szHint.height,
3368 r->TermWin.ext_bwidth,
3369 XDEPTH, InputOutput,
3370 XVISUAL,
3371 CWBackPixel | CWBorderPixel
3372 | CWColormap, &attributes);
3373 #else
3374 r->TermWin.parent = XCreateSimpleWindow(r->Xdisplay, parent,
3375 r->szHint.x, r->szHint.y,
3376 r->szHint.width,
3377 r->szHint.height,
3378 r->TermWin.ext_bwidth,
3379 r->pixColorsFocus[Color_border],
3380 r->pixColorsFocus[Color_bg]);
3381 #endif
3382
3383 #ifdef XFT_SUPPORT
3384 if (ISSET_OPTION(r, Opt_xft))
3385 {
3386 /* create XFT draw, test only */
3387 XftDraw* xftdraw = XftDrawCreate( r->Xdisplay,
3388 r->TermWin.parent, XVISUAL,
3389 XCMAP);
3390 if (xftdraw)
3391 {
3392 XftDrawDestroy (xftdraw);
3393 /* some cleanup work if successfully create xft window */
3394 # ifdef POINTER_BLANK
3395 /*
3396 * 2006-01-21 gi1242: I'm not sure why pointer blank is disabled
3397 * with xft. It works fine for me, so I re-enabled it.
3398 */
3399 # if 0
3400 /* disable pointer blank */
3401 UNSET_OPTION(r, Opt_pointerBlank);
3402 # endif
3403 # endif
3404 }
3405 }
3406 #endif
3407
3408
3409 # ifdef HAVE_X11_SM_SMLIB_H
3410 if (ISSET_OPTION(r, Opt2_enableSessionMgt))
3411 rxvt_session_init (r);
3412 # endif
3413
3414
3415 /*
3416 * Now set window properties, like title, icon name and hints
3417 */
3418 /* window title name */
3419 win_prop.value = (unsigned char*) r->h->rs[Rs_title];
3420 win_prop.nitems = STRLEN (win_prop.value);
3421 win_prop.encoding = XA_STRING;
3422 win_prop.format = 8;
3423 /* icon name */
3424 icon_prop.value = (unsigned char*) r->h->rs[Rs_iconName];
3425 icon_prop.nitems = STRLEN (icon_prop.value);
3426 icon_prop.encoding = XA_STRING;
3427 icon_prop.format = 8;
3428 /* window manager hints */
3429 wm_hint.flags = (InputHint | StateHint | WindowGroupHint);
3430 wm_hint.input = True;
3431 wm_hint.initial_state = ISSET_OPTION(r, Opt_iconic) ? IconicState
3432 : NormalState;
3433 wm_hint.window_group = r->TermWin.parent;
3434 /* window icon hint */
3435 #ifdef HAVE_LIBXPM
3436 if( r->h->rs[Rs_appIcon] )
3437 {
3438 Pixmap appIcon, appIconMask;
3439
3440 XpmReadFileToPixmap( r->Xdisplay, r->TermWin.parent,
3441 (char*) r->h->rs[Rs_appIcon], &appIcon, &appIconMask, 0);
3442
3443 if( appIcon != None && appIconMask != None ) {
3444 wm_hint.icon_pixmap = appIcon;
3445 wm_hint.icon_mask = appIconMask;
3446 wm_hint.flags |= IconPixmapHint | IconMaskHint;
3447 }
3448 }
3449 #endif /* HAVE_LIBXPM */
3450 /* class hints */
3451 class_hint.res_name = (char*) r->h->rs[Rs_name];
3452 class_hint.res_class = (char*) APL_CLASS;
3453 XSetWMProperties (r->Xdisplay, r->TermWin.parent,
3454 &win_prop, &icon_prop, (char**)argv, argc,
3455 &r->szHint, &wm_hint, &class_hint);
3456
3457 #if 0 /* If the pixmap's are free'ed, then the WM will not display them. */
3458 if( wm_hint.flags & IconPixmapHint )
3459 {
3460 XFreePixmap( r->Xdisplay, wm_hint.icon_pixmap );
3461 XFreePixmap( r->Xdisplay, wm_hint.icon_mask );
3462 }
3463 #endif
3464
3465 /* set terminal title */
3466 rxvt_set_term_title (r, win_prop.value);
3467 /* set icon title */
3468 rxvt_set_icon_name (r, icon_prop.value);
3469 /* command line */
3470 XSetCommand (r->Xdisplay, r->TermWin.parent, (char**) argv, argc);
3471
3472 /* override redirect */
3473 if (ISSET_OPTION(r, Opt2_overrideRedirect))
3474 {
3475 XSetWindowAttributes attrib;
3476 attrib.override_redirect = True;
3477 XChangeWindowAttributes(r->Xdisplay, r->TermWin.parent,
3478 CWOverrideRedirect, &attrib);
3479 }
3480
3481 #ifndef NO_FRILLS
3482 XChangeProperty (r->Xdisplay, r->TermWin.parent,
3483 r->h->xa[XA_NET_WM_PID], XA_CARDINAL, 32,
3484 PropModeReplace, (unsigned char*) &pid, 1);
3485 #endif
3486
3487 if (ISSET_OPTION(r, Opt2_borderLess))
3488 {
3489 rxvt_set_borderless (r);
3490 }
3491 if (r->h->rs[Rs_desktop])
3492 {
3493 CARD32 desktop = (CARD32) atoi (r->h->rs[Rs_desktop]);
3494 rxvt_set_desktop (r, desktop);
3495 }
3496
3497 /*
3498 * set WM_CLIENT_LEADER property so that session management proxy can handle
3499 * us even session management is not enabled.
3500 */
3501 if (IS_ATOM(r->h->xa[XA_WM_CLIENT_LEADER]))
3502 XChangeProperty( r->Xdisplay, r->TermWin.parent,
3503 r->h->xa[XA_WM_CLIENT_LEADER], XA_WINDOW, 32,
3504 PropModeReplace, (unsigned char*) &(r->TermWin.parent), 1L );
3505
3506 # ifdef HAVE_X11_SM_SMLIB_H
3507 if (NOT_NULL(r->TermWin.sm_conn) &&
3508 NOT_NULL(r->TermWin.sm_client_id) &&
3509 STRCMP (r->TermWin.sm_client_id, "")
3510 )
3511 {
3512 if (IS_ATOM(r->h->xa[XA_SM_CLIENT_ID]))
3513 XChangeProperty(r->Xdisplay, r->TermWin.parent,
3514 r->h->xa[XA_SM_CLIENT_ID], XA_STRING, 8,
3515 PropModeReplace,
3516 (unsigned char*) r->TermWin.sm_client_id,
3517 STRLEN(r->TermWin.sm_client_id));
3518 }
3519 # endif /* HAVE_X11_SM_SMLIB_H */
3520
3521
3522 #ifdef TRANSPARENT
3523 r->TermWin.parenttree[0] = r->TermWin.parent;
3524 for (i = 1; i < PARENT_NUMBER; i ++)
3525 UNSET_WIN(r->TermWin.parenttree[i]);
3526
3527 /*
3528 * XXX 2006-01-02 gi1242: This is inefficient. If window is pseudo
3529 * transparent, then the background pixmap will be reset later to something
3530 * else.
3531 */
3532 #if 0
3533 if (ISSET_OPTION(r, Opt_transparent))
3534 {
3535 XSetWindowBackgroundPixmap (r->Xdisplay, r->TermWin.parent,
3536 ParentRelative);
3537 }
3538 #endif
3539 #endif /* TRANSPARENT */
3540
3541
3542 XSelectInput(r->Xdisplay, r->TermWin.parent,
3543 (KeyPressMask
3544 #if defined(MOUSE_WHEEL) && defined(MOUSE_SLIP_WHEELING)
3545 | KeyReleaseMask
3546 #endif
3547 | FocusChangeMask
3548 #ifdef MONITOR_ENTER_LEAVE
3549 | EnterWindowMask | LeaveWindowMask
3550 #endif
3551 | VisibilityChangeMask
3552 | StructureNotifyMask));
3553
3554
3555 /*
3556 ** vt cursor: Black-on-White is standard, but this is more
3557 ** popular
3558 */
3559 r->term_pointer = XCreateFontCursor(r->Xdisplay, XC_xterm);
3560 /* scrollbar/menubar/tabbar window pointer */
3561 r->h->bar_pointer = XCreateFontCursor(r->Xdisplay, XC_left_ptr);
3562
3563 #ifdef POINTER_BLANK
3564 if (NOTSET_OPTION(r, Opt_pointerBlank))
3565 UNSET_CURSOR(r->h->blank_pointer);
3566 else
3567 r->h->blank_pointer = XCreateGlyphCursor(r->Xdisplay,
3568 r->TermWin.font->fid, r->TermWin.font->fid, ' ', ' ',
3569 (XColor*) &blackcolour, (XColor*) &blackcolour);
3570 #endif
3571
3572
3573 /* graphics context for the vt window */
3574 #ifdef XFT_SUPPORT
3575 if (NOTSET_OPTION(r, Opt_xft))
3576 #endif
3577 gcvalue.font = r->TermWin.font->fid;
3578 gcvalue.foreground = r->pixColorsFocus[Color_fg];
3579 gcvalue.background = r->pixColorsFocus[Color_bg];
3580 gcvalue.graphics_exposures = 1;
3581 gcmask = GCForeground | GCBackground | GCGraphicsExposures;
3582 #ifdef XFT_SUPPORT
3583 if (NOTSET_OPTION(r, Opt_xft))
3584 #endif
3585 gcmask |= GCFont;
3586 r->TermWin.gc = XCreateGC(r->Xdisplay, r->TermWin.parent,
3587 gcmask, &gcvalue);
3588
3589 #ifdef HAVE_SCROLLBARS
3590 rxvt_scrollbar_create (r);
3591 if (ISSET_OPTION(r, Opt_scrollBar))
3592 {
3593 rxvt_scrollbar_show (r);
3594 }
3595 #endif
3596 #ifdef HAVE_MENUBAR
3597 if (r->h->rs[Rs_menu] && STRCASECMP( r->h->rs[Rs_menu], "none"))
3598 {
3599 /*
3600 * Only load menubar if arg of -menu option is not none
3601 */
3602 rxvt_menubar_load_file (r, (unsigned char*) r->h->rs[Rs_menu]);
3603 }
3604 else rxvt_menubar_load_file( r, (unsigned char*) "default.menu");
3605
3606 rxvt_menubar_create (r);
3607 if (ISSET_OPTION(r, Opt_showMenu))
3608 rxvt_menubar_show (r);
3609
3610 /*
3611 * 2006-05-28 gi1242: If popup menu 1 is not defined, set it to an empty
3612 * menu (so that the tab list will be popped up on control clicks and right
3613 * clicks on the tabbar).
3614 */
3615 if (IS_NULL(r->h->popupMenu[0]))
3616 {
3617 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "Setting popup menu 1 to a tab list\n"));
3618 r->h->popupMenu[0] = (menu_t *) rxvt_calloc( 1, sizeof(menu_t) );
3619
3620 r->h->popupMenu[0]->len = sizeof( "Switch to tab" );
3621 r->h->popupMenu[0]->name = (unsigned char*) STRDUP ("Switch to tab");
3622 }
3623 # endif
3624
3625 rxvt_tabbar_create (r);
3626 if (NOTSET_OPTION(r, Opt2_hideTabbar))
3627 rxvt_tabbar_show (r);
3628
3629 XMapWindow (r->Xdisplay, r->TermWin.parent);
3630
3631 /*
3632 * We have to wait till our window is mapped before we can set the maximized
3633 * or fullscreen options.
3634 */
3635 if( ISSET_OPTION(r, Opt2_maximized))
3636 ewmh_message( r->Xdisplay, XROOT, r->TermWin.parent,
3637 XInternAtom( r->Xdisplay, "_NET_WM_STATE", True),
3638 _NET_WM_STATE_ADD,
3639 XInternAtom( r->Xdisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", True),
3640 XInternAtom( r->Xdisplay, "_NET_WM_STATE_MAXIMIZED_VERT", True),
3641 0, 0);
3642 else if (ISSET_OPTION (r, Opt2_fullscreen))
3643 ewmh_message( r->Xdisplay, XROOT, r->TermWin.parent,
3644 XInternAtom( r->Xdisplay, "_NET_WM_STATE", True),
3645 _NET_WM_STATE_ADD,
3646 XInternAtom( r->Xdisplay, "_NET_WM_STATE_FULLSCREEN", True),
3647 0, 0, 0);
3648 }
3649
3650 /*----------------------------------------------------------------------*/
3651 /*
3652 * Executes a command in the background, and returns immediately. Returns 1 on
3653 * success, 0 otherwise.
3654 */
3655 int
rxvt_async_exec(rxvt_t * r,const char * cmd)3656 rxvt_async_exec( rxvt_t *r, const char *cmd)
3657 {
3658 int pid;
3659 int argc;
3660 char **argv;
3661
3662 if( r->nAsyncChilds >= MAX_CHILDS )
3663 {
3664 rxvt_msg (DBG_ERROR, DBG_INIT, "Too many childs."
3665 " Increase MAX_CHILDS in src/feature.h" );
3666 return 0;
3667 }
3668
3669 pid = fork();
3670 switch( pid )
3671 {
3672 case -1:
3673 rxvt_msg (DBG_ERROR, DBG_INIT, "Unable to fork" );
3674 return 0; /* Failure */
3675 /* NOT REACHED */
3676
3677 case 0:
3678 /*
3679 * Close all file descriptors, and reset signal masks to their
3680 * default values before exec'ing the child process.
3681 */
3682 clean_sigmasks_and_fds( r, ATAB(r) );
3683
3684 argv = rxvt_string_to_argv( cmd, &argc );
3685
3686 execvp( argv[0], argv );
3687
3688 rxvt_msg (DBG_ERROR, DBG_INIT, "Failed to exec %s", argv[0] );
3689 exit(1);
3690 /* NOT REACHED */
3691
3692 default:
3693 rxvt_dbgmsg ((DBG_VERBOSE, DBG_INIT, "Forked %s", cmd));
3694 r->asyncChilds[ r->nAsyncChilds++ ] = pid;
3695 return 1;
3696 }
3697 }
3698
3699
3700 /*
3701 * Run the command in a subprocess and return a file descriptor for the
3702 * master end of the pseudo-teletype pair with the command talking to
3703 * the slave.
3704 */
3705 /* EXTPROTO */
3706 int
rxvt_run_command(rxvt_t * r,int page,const char ** argv)3707 rxvt_run_command(rxvt_t *r, int page, const char **argv)
3708 {
3709 int cfd, er;
3710
3711 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "%s(%d, argv)", __func__, page));
3712
3713 /* get master (pty) */
3714 if ((cfd = rxvt_get_pty(&(PVTS(r, page)->tty_fd),
3715 (char**) &(PVTS(r, page)->ttydev))) < 0)
3716 {
3717 rxvt_msg (DBG_ERROR, DBG_INIT, "can't open pseudo-tty");
3718 return -1;
3719 }
3720 #ifdef FD_SETSIZE
3721 if (r->Xfd > FD_SETSIZE || cfd > FD_SETSIZE)
3722 {
3723 rxvt_msg (DBG_ERROR, DBG_INIT, "fd too high: %d max", FD_SETSIZE);
3724 return -1;
3725 }
3726 #endif
3727 fcntl(cfd, F_SETFL, O_NDELAY);
3728
3729 /* get slave (tty) */
3730 if (PVTS(r, page)->tty_fd < 0)
3731 {
3732 #if !defined(NO_SETOWNER_TTYDEV) && !defined(OS_CYGWIN)
3733 rxvt_privileged_ttydev(r, page, SAVE);
3734 #endif
3735 if ((PVTS(r, page)->tty_fd = rxvt_get_tty(PVTS(r, page)->ttydev)) < 0)
3736 {
3737 close(cfd);
3738 rxvt_msg (DBG_ERROR, DBG_INIT, "can't open slave tty %s", PVTS(r, page)->ttydev);
3739 return -1;
3740 }
3741 }
3742
3743 /* Get tty mode before fork */
3744 #ifndef NO_BACKSPACE_KEY
3745 if (r->h->key_backspace[0] && !r->h->key_backspace[1])
3746 er = r->h->key_backspace[0];
3747 else if (STRCMP(r->h->key_backspace, "DEC") == 0)
3748 er = '\177'; /* the initial state anyway */
3749 else
3750 #endif
3751 er = -1;
3752 rxvt_get_ttymode(&(PVTS(r, page)->tio), er);
3753
3754
3755 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "argv = 0x%x\n", (unsigned int) argv));
3756 #ifndef __QNX__
3757 /*
3758 * Spin off the command interpreter
3759 */
3760 switch (PVTS(r, page)->cmd_pid = fork())
3761 {
3762 case -1:
3763 rxvt_msg (DBG_ERROR, DBG_INIT, "can't fork");
3764 close (cfd);
3765 return -1;
3766
3767 case 0:
3768 /*
3769 * To debug the child, follow these steps:
3770 *
3771 * - enable sleep in the following
3772 * - launch gdb, set breakpoint before fork
3773 * - run the program, step over fork, then get child pid
3774 * - launch another gdb, attach to child process via pid
3775 * - in child's gdb, set breakpoint after sleep
3776 * - run 'continue' in child's gdb, debug child process
3777 */
3778 #if 0
3779 sleep(10);
3780 #endif
3781
3782
3783 if(
3784 rxvt_control_tty( PVTS(r, page)->tty_fd,
3785 PVTS(r, page)->ttydev ) < 0
3786 )
3787 {
3788 rxvt_msg (DBG_ERROR, DBG_INIT, "Could not obtain control of tty");
3789 }
3790 else
3791 {
3792 /*
3793 * Reopen stdin, stdout and stderr over the tty file
3794 * descriptor
3795 */
3796 dup2( PVTS(r, page)->tty_fd, STDIN_FILENO );
3797 dup2( PVTS(r, page)->tty_fd, STDOUT_FILENO );
3798 dup2( PVTS(r, page)->tty_fd, STDERR_FILENO );
3799
3800 clean_sigmasks_and_fds( r, page );
3801
3802 /*
3803 * Spin off command interpreter.
3804 */
3805 rxvt_run_child(r, page, argv);
3806
3807 /*
3808 * If we got here, then we failed to exec the child process.
3809 */
3810 rxvt_msg (DBG_ERROR, DBG_INIT, "Could not execute %s.\n", (argv && argv[0]) ? argv[0] : "shell");
3811 }
3812
3813 /* Something went wrong. Kill the child. */
3814 if(
3815 !(PVTS(r,page)->holdOption & HOLD_STATUSBIT) &&
3816 !(PVTS(r,page)->holdOption & HOLD_ALWAYSBIT)
3817 )
3818 /* If tab won't be held open, wait a little */
3819 sleep(5);
3820 exit( EXIT_FAILURE );
3821
3822 /* NOT REACHED */
3823
3824 default:
3825 {
3826 #if defined(HAVE_STRUCT_UTMP) && defined(HAVE_TTYSLOT)
3827 int fdstdin;
3828
3829 fdstdin = dup(STDIN_FILENO);
3830 dup2(PVTS(r, page)->tty_fd, STDIN_FILENO);
3831 #endif
3832 #ifdef UTMP_SUPPORT
3833 # ifdef UTEMPTER_SUPPORT
3834 /* utempter hack, it needs cmd_fd */
3835 PVTS(r, page)->cmd_fd = cfd;
3836 # endif
3837 rxvt_privileged_utmp(r, page, SAVE);
3838 # ifdef UTEMPTER_SUPPORT
3839 /* utempter hack, restore cmd_fd */
3840 PVTS(r, page)->cmd_fd = -1;
3841 # endif
3842 #endif
3843 #if defined(HAVE_STRUCT_UTMP) && defined(HAVE_TTYSLOT)
3844 dup2(fdstdin, STDIN_FILENO);
3845 close(fdstdin);
3846 #endif
3847 }
3848
3849 /*
3850 * keep STDERR_FILENO, PVTS(r, page)->cmd_fd, r->Xfd open
3851 */
3852 close(PVTS(r, page)->tty_fd);
3853 PVTS(r, page)->tty_fd = -1;
3854 break;
3855 }
3856 #else /* __QNX__ uses qnxspawn() */
3857 fchmod(PVTS(r, page)->tty_fd, 0622);
3858 fcntl(PVTS(r, page)->tty_fd, F_SETFD, FD_CLOEXEC);
3859 fcntl(cfd, F_SETFD, FD_CLOEXEC);
3860 PVTS(r, page)->cmd_fd = cfd;
3861
3862 if (rxvt_run_child(r, page, argv) == -1)
3863 /*exit(EXIT_FAILURE);*/
3864 return -1;
3865 #endif
3866
3867 return cfd;
3868 }
3869
3870
3871 /* ------------------------------------------------------------------------- *
3872 * CHILD PROCESS OPERATIONS *
3873 * ------------------------------------------------------------------------- */
3874
3875 /*
3876 * Reset signal masks to their default values, and close all open file
3877 * descriptors.
3878 */
3879 /* EXTPROTO */
3880 void
clean_sigmasks_and_fds(rxvt_t * r,int page)3881 clean_sigmasks_and_fds( rxvt_t* r, int page )
3882 {
3883 #ifdef SIGTSTP
3884 struct sigaction ignore;
3885 #endif
3886 struct sigaction deflt;
3887 register int i;
3888
3889 /* Close all file descriptors except STDXXX */
3890 for (i = STDERR_FILENO + 1; i < r->num_fds; i ++)
3891 close (i);
3892 if (PVTS(r, page)->tty_fd > 2)
3893 {
3894 close (PVTS(r, page)->tty_fd);
3895 PVTS(r, page)->tty_fd = -1;
3896 }
3897
3898 /* reset signal handlers */
3899 deflt.sa_handler = SIG_DFL;
3900 deflt.sa_flags = 0;
3901 sigemptyset( &deflt.sa_mask );
3902
3903 sigaction( SIGINT, &deflt, NULL );
3904 sigaction( SIGQUIT, &deflt, NULL );
3905 sigaction( SIGTERM, &deflt, NULL );
3906 sigaction( SIGHUP, &deflt, NULL );
3907 sigaction( SIGPIPE, &deflt, NULL );
3908 sigaction( SIGCHLD, &deflt, NULL );
3909
3910 /*
3911 * Mimick login's behavior by disabling the job control signals a shell that
3912 * wants them can turn them back on
3913 */
3914 #ifdef SIGTSTP
3915 ignore.sa_handler = SIG_IGN;
3916 ignore.sa_flags = 0;
3917 sigemptyset( &ignore.sa_mask );
3918
3919 sigaction( SIGTSTP, &ignore, NULL );
3920 sigaction( SIGTTIN, &ignore, NULL );
3921 sigaction( SIGTTOU, &ignore, NULL );
3922 #endif /* SIGTSTP */
3923 }
3924
3925
3926 /*
3927 * The only open file descriptor is the slave tty - so no error messages.
3928 * returns are fatal
3929 */
3930 /* INTPROTO */
3931 int
rxvt_run_child(rxvt_t * r,int page,const char ** argv)3932 rxvt_run_child(rxvt_t* r, int page, const char **argv)
3933 {
3934 char* login;
3935
3936
3937 /* rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "argv = %x\n", argv)); */
3938
3939 /* init terminal attributes */
3940 SET_TTYMODE( STDIN_FILENO, &(PVTS(r, page)->tio) );
3941
3942 if (ISSET_OPTION(r, Opt_console)) /* be virtual console, fail
3943 * silently */
3944 {
3945 #ifdef TIOCCONS
3946 unsigned int on = 1;
3947 ioctl(STDIN_FILENO, TIOCCONS, &on);
3948 #elif defined (SRIOCSREDIR)
3949 int fd;
3950 fd = open( CONSOLE, O_WRONLY, 0 );
3951 if (fd >= 0)
3952 {
3953 if( ioctl( fd, SRIOCSREDIR, NULL ) < 0 )
3954 close( fd );
3955 }
3956 #endif /* SRIOCSREDIR */
3957 }
3958
3959 /* set window size */
3960 rxvt_tt_winsize( STDIN_FILENO, r->TermWin.ncol, r->TermWin.nrow, 0 );
3961
3962 #ifndef __QNX__
3963 /* command interpreter path */
3964 if (NOT_NULL(argv))
3965 {
3966 int i;
3967 for (i = 0; argv[i]; i++)
3968 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "argv [%d] = \"%s\"\n", i, argv[i]));
3969 execvp(argv[0], (char *const *)argv);
3970 /* no error message: STDERR is closed! */
3971 }
3972 else
3973 {
3974 const char *argv0, *shell;
3975
3976 if (IS_NULL(shell = getenv("SHELL")) || ((char) 0 == *shell) )
3977 {
3978 # ifdef HAVE_GETPWUID
3979 struct passwd* pwent = getpwuid( getuid () );
3980
3981 if (IS_NULL(pwent) ||
3982 IS_NULL(shell = pwent->pw_shell) ||
3983 (char) 0 == *shell
3984 )
3985 # endif /* HAVE_GETPWUID */
3986 shell = "/bin/sh";
3987 }
3988
3989 argv0 = (const char *) rxvt_r_basename( shell);
3990 if (ISSET_OPTION(r, Opt_loginShell))
3991 {
3992 int l = STRLEN(argv0) + 2;
3993 if (l <= 0 || l > 4096) /* possible integer overflow */
3994 l = 4096;
3995 login = rxvt_malloc(l * sizeof(char));
3996
3997 login[0] = '-';
3998 STRNCPY(&login[1], argv0, l-2);
3999 login[l-1] = (char) 0;
4000 argv0 = login;
4001 }
4002 execlp( shell, argv0, NULL );
4003 /* no error message: STDERR is closed! */
4004 }
4005 #else /* __QNX__ uses qnxspawn() */
4006 {
4007 char iov_a[10] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
4008 char* command = NULL, fullcommand[_MAX_PATH];
4009 char** arg_v, *arg_a[2] = { NULL, NULL };
4010
4011 if (argv != NULL)
4012 {
4013 if (access(argv[0], X_OK) == -1)
4014 {
4015 if (IS_NULL(STRCHR(argv[0], '/')))
4016 {
4017 searchenv(argv[0], "PATH", fullcommand);
4018 if (fullcommand[0] != '\0')
4019 command = fullcommand;
4020 }
4021 if (access(command, X_OK) == -1)
4022 return -1;
4023 }
4024 else
4025 command = argv[0];
4026 arg_v = argv;
4027 }
4028 else
4029 {
4030 if (IS_NULL(command = getenv("SHELL")) ||
4031 (char) 0 == *command)
4032 command = "/bin/sh";
4033
4034 arg_a[0] = my_basename(command);
4035 if (ISSET_OPTION(r, Opt_loginShell))
4036 {
4037 int l = STRLEN(arg_a[0]) + 2;
4038 if (l <= 0 || l > 4096) /* possible integer overflow */
4039 l = 4096;
4040 login = rxvt_malloc(l * sizeof(char));
4041
4042 login[0] = '-';
4043 STRNCPY(&login[1], arg_a[0], l-2);
4044 login[l-1] = (char) 0;
4045 arg_a[0] = login;
4046 }
4047 arg_v = arg_a;
4048 }
4049 iov_a[0] = iov_a[1] = iov_a[2] = PVTS(r, page)->tty_fd;
4050 PVTS(r, page)->cmd_pid = qnx_spawn(0, 0, 0, -1, -1,
4051 _SPAWN_SETSID | _SPAWN_TCSETPGRP,
4052 command, arg_v, environ, iov_a, 0);
4053 if (login)
4054 rxvt_free(login);
4055 close(PVTS(r, page)->tty_fd);
4056 PVTS(r, page)->tty_fd = -1;
4057 return PVTS(r, page)->cmd_fd;
4058 }
4059 #endif
4060 return -1;
4061 }
4062
4063 /* ------------------------------------------------------------------------- *
4064 * GET TTY CURRENT STATE *
4065 * ------------------------------------------------------------------------- */
4066 /* rxvt_get_ttymode() */
4067 /* INTPROTO */
4068 void
rxvt_get_ttymode(ttymode_t * tio,int erase)4069 rxvt_get_ttymode(ttymode_t *tio, int erase)
4070 {
4071 #ifdef HAVE_TERMIOS_H
4072 /*
4073 * standard System V termios interface
4074 */
4075 if (GET_TERMIOS(STDIN_FILENO, tio) < 0)
4076 {
4077 /* return error - use system defaults */
4078 tio->c_cc[VINTR] = CINTR;
4079 tio->c_cc[VQUIT] = CQUIT;
4080 tio->c_cc[VERASE] = CERASE;
4081 tio->c_cc[VKILL] = CKILL;
4082 tio->c_cc[VSTART] = CSTART;
4083 tio->c_cc[VSTOP] = CSTOP;
4084 tio->c_cc[VSUSP] = CSUSP;
4085 # ifdef VDSUSP
4086 tio->c_cc[VDSUSP] = CDSUSP;
4087 # endif
4088 # ifdef VREPRINT
4089 tio->c_cc[VREPRINT] = CRPRNT;
4090 # endif
4091 # ifdef VDISCRD
4092 tio->c_cc[VDISCRD] = CFLUSH;
4093 # endif
4094 # ifdef VWERSE
4095 tio->c_cc[VWERSE] = CWERASE;
4096 # endif
4097 # ifdef VLNEXT
4098 tio->c_cc[VLNEXT] = CLNEXT;
4099 # endif
4100 }
4101 tio->c_cc[VEOF] = CEOF;
4102 tio->c_cc[VEOL] = VDISABLE;
4103 # ifdef VEOL2
4104 tio->c_cc[VEOL2] = VDISABLE;
4105 # endif
4106 # ifdef VSWTC
4107 tio->c_cc[VSWTC] = VDISABLE;
4108 # endif
4109 # ifdef VSWTCH
4110 tio->c_cc[VSWTCH] = VDISABLE;
4111 # endif
4112 # if VMIN != VEOF
4113 tio->c_cc[VMIN] = 1;
4114 # endif
4115 # if VTIME != VEOL
4116 tio->c_cc[VTIME] = 0;
4117 # endif
4118 if (erase != -1)
4119 tio->c_cc[VERASE] = (char)erase;
4120
4121 /* input modes */
4122 tio->c_iflag = (BRKINT | IGNPAR | ICRNL
4123 # ifdef IMAXBEL
4124 | IMAXBEL
4125 # endif
4126 | IXON);
4127
4128 /* output modes */
4129 tio->c_oflag = (OPOST | ONLCR);
4130
4131 /* control modes */
4132 tio->c_cflag = (CS8 | CREAD);
4133
4134 /* line discipline modes */
4135 tio->c_lflag = (ISIG | ICANON | IEXTEN | ECHO
4136 # if defined (ECHOCTL) && defined (ECHOKE)
4137 | ECHOCTL | ECHOKE
4138 # endif
4139 | ECHOE | ECHOK);
4140 # else /* HAVE_TERMIOS_H */
4141
4142 /*
4143 * sgtty interface
4144 */
4145
4146 /* get parameters -- gtty */
4147 if (ioctl(STDIN_FILENO, TIOCGETP, &(tio->sg)) < 0)
4148 {
4149 tio->sg.sg_erase = CERASE; /* ^H */
4150 tio->sg.sg_kill = CKILL; /* ^U */
4151 }
4152 if (erase != -1)
4153 tio->sg.sg_erase = (char)erase;
4154
4155 tio->sg.sg_flags = (CRMOD | ECHO | EVENP | ODDP);
4156
4157 /* get special characters */
4158 if (ioctl(STDIN_FILENO, TIOCGETC, &(tio->tc)) < 0)
4159 {
4160 tio->tc.t_intrc = CINTR; /* ^C */
4161 tio->tc.t_quitc = CQUIT; /* ^\ */
4162 tio->tc.t_startc = CSTART; /* ^Q */
4163 tio->tc.t_stopc = CSTOP; /* ^S */
4164 tio->tc.t_eofc = CEOF; /* ^D */
4165 tio->tc.t_brkc = -1;
4166 }
4167
4168 /* get local special chars */
4169 if (ioctl(STDIN_FILENO, TIOCGLTC, &(tio->lc)) < 0)
4170 {
4171 tio->lc.t_suspc = CSUSP; /* ^Z */
4172 tio->lc.t_dsuspc = CDSUSP; /* ^Y */
4173 tio->lc.t_rprntc = CRPRNT; /* ^R */
4174 tio->lc.t_flushc = CFLUSH; /* ^O */
4175 tio->lc.t_werasc = CWERASE; /* ^W */
4176 tio->lc.t_lnextc = CLNEXT; /* ^V */
4177 }
4178
4179 /* get line discipline */
4180 ioctl(STDIN_FILENO, TIOCGETD, &(tio->line));
4181 # ifdef NTTYDISC
4182 tio->line = NTTYDISC;
4183 # endif /* NTTYDISC */
4184 tio->local = (LCRTBS | LCRTERA | LCTLECH | LPASS8 | LCRTKIL);
4185 #endif /* HAVE_TERMIOS_H */
4186
4187 /*
4188 * Debugging
4189 */
4190 #ifdef DEBUG
4191 #ifdef HAVE_TERMIOS_H
4192 /* c_iflag bits */
4193 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "Input flags\n"));
4194
4195 /* cpp token stringize doesn't work on all machines <sigh> */
4196 # define FOO(flag,name) \
4197 if ((tio->c_iflag) & flag) \
4198 rxvt_msg (DBG_DEBUG, DBG_INIT, "%s ", name)
4199
4200 /* c_iflag bits */
4201 FOO(IGNBRK, "IGNBRK");
4202 FOO(BRKINT, "BRKINT");
4203 FOO(IGNPAR, "IGNPAR");
4204 FOO(PARMRK, "PARMRK");
4205 FOO(INPCK, "INPCK");
4206 FOO(ISTRIP, "ISTRIP");
4207 FOO(INLCR, "INLCR");
4208 FOO(IGNCR, "IGNCR");
4209 FOO(ICRNL, "ICRNL");
4210 FOO(IXON, "IXON");
4211 FOO(IXOFF, "IXOFF");
4212 # ifdef IUCLC
4213 FOO(IUCLC, "IUCLC");
4214 # endif
4215 # ifdef IXANY
4216 FOO(IXANY, "IXANY");
4217 # endif
4218 # ifdef IMAXBEL
4219 FOO(IMAXBEL, "IMAXBEL");
4220 # endif
4221 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "\n"));
4222
4223 # undef FOO
4224 # define FOO(entry, name) \
4225 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "%-8s = %#04o\n", name, tio->c_cc [entry]))
4226
4227 FOO(VINTR, "VINTR");
4228 FOO(VQUIT, "VQUIT");
4229 FOO(VERASE, "VERASE");
4230 FOO(VKILL, "VKILL");
4231 FOO(VEOF, "VEOF");
4232 FOO(VEOL, "VEOL");
4233 # ifdef VEOL2
4234 FOO(VEOL2, "VEOL2");
4235 # endif
4236 # ifdef VSWTC
4237 FOO(VSWTC, "VSWTC");
4238 # endif
4239 # ifdef VSWTCH
4240 FOO(VSWTCH, "VSWTCH");
4241 # endif
4242 FOO(VSTART, "VSTART");
4243 FOO(VSTOP, "VSTOP");
4244 FOO(VSUSP, "VSUSP");
4245 # ifdef VDSUSP
4246 FOO(VDSUSP, "VDSUSP");
4247 # endif
4248 # ifdef VREPRINT
4249 FOO(VREPRINT, "VREPRINT");
4250 # endif
4251 # ifdef VDISCRD
4252 FOO(VDISCRD, "VDISCRD");
4253 # endif
4254 # ifdef VWERSE
4255 FOO(VWERSE, "VWERSE");
4256 # endif
4257 # ifdef VLNEXT
4258 FOO(VLNEXT, "VLNEXT");
4259 # endif
4260 rxvt_dbgmsg ((DBG_DEBUG, DBG_INIT, "\n"));
4261 # undef FOO
4262 # endif /* HAVE_TERMIOS_H */
4263 #endif /* DEBUG */
4264 }
4265
4266 /*----------------------- end-of-file (C source) -----------------------*/
4267