ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/init.C
Revision: 1.346
Committed: Tue Jun 21 12:03:56 2016 UTC (7 years, 11 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.345: +35 -0 lines
Log Message:
24-bit direct color support (patch by Fengguang Wu)

Support directly setting RGB fg/bg colors via ISO-8613-3 24-bit
ANSI color escapes:

  ESC[38;2;<r>;<g>;<b>m Select RGB foreground color
  ESC[48;2;<r>;<g>;<b>m Select RGB background color

The killer applications for me are vim in tmux. It'll not only modernize
their look and feeling, but also bring more eye friendly color schemes.
Very helpful for long time programmers.

To avoid memory overheads and keep the patch non-intrusive, it takes the
approach to adapt the nearest color in an hidden 6x6x4 (88-color mode)
or 7x7x5 (256-color mode) color cube to the new 24-bit RGB color.

The pros/cons are:

+) least memory footprint (close to 0)
   comparing to konsole, gnome-terminal etc. real 24-bit arrays

+) exact colors and excellent user feelings
   comparing to xterm, mlterm, etc. approximating to 256 palette

+) usable in both the existing 88/256-color modes

   Most vim GUI color schemes show up the same as gvim in rxvt-unicode's
   88-color mode, not to mention the 256-color mode. Typical applications
   only use one or two dozens of colors at the same time.

-) may not be able to show 2+ close 24-bit colors

   RGB colors close to each other will likely fall into the same slot in
   the 6x6x4 or 7x7x5 color cube. If necessary, it could be improved
   effectively by implementing some collision avoidance logic, trying to
   find empty/eldest slot in the +1/-1 r/g/b indices (ie. 3-8 neighbors).

The CPU overheads of map_rgb24_color() look ignorable: I feel no
perceptible slow down when doing vim operations in 24-bit color mode.

A micro benchmark running a test script from [1]:

% time (for i in {1..100}; do 24-bit-color.sh; done)

vanilla rxvt-unicode
====================
  2.42s user 1.88s system 31% cpu 13.555 total
  2.59s user 1.74s system 31% cpu 13.615 total
  2.46s user 1.85s system 31% cpu 13.631 total

THIS PATCH (adapt hidden color cube to 24-bit)
==============================================
  2.33s user 1.97s system 31% cpu 13.598 total
  2.46s user 1.89s system 31% cpu 13.613 total
  2.51s user 1.82s system 31% cpu 13.556 total

https://github.com/spudowiar/rxvt-unicode (real 24-bit array)
=============================================================
  2.61s user 1.75s system 31% cpu 13.721 total
  2.48s user 1.82s system 31% cpu 13.566 total
  2.60s user 1.76s system 31% cpu 13.631 total

USE_256_COLORS is defined in all the above rxvt-unicode builds.

References:

[1] True Colour (16 million colours) support in various terminal
    applications and terminals
    https://gist.github.com/XVilka/8346728

[2] https://en.wikipedia.org/wiki/ANSI_escape_code#Colors

File Contents

# Content
1 /*----------------------------------------------------------------------*
2 * File: init.C
3 *----------------------------------------------------------------------*
4 *
5 * All portions of code are copyright by their respective author/s.
6 * Copyright (c) 1992 John Bovey, University of Kent at Canterbury <jdb@ukc.ac.uk>
7 * - original version
8 * Copyright (c) 1994 Robert Nation <nation@rocket.sanders.lockheed.com>
9 * - extensive modifications
10 * Copyright (c) 1996 Chuck Blake <cblake@BBN.COM>
11 * Copyright (c) 1997 mj olesen <olesen@me.queensu.ca>
12 * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
13 * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
14 * - extensive modifications
15 * Copyright (c) 2003-2008 Marc Lehmann <schmorp@schmorp.de>
16 * Copyright (c) 2015 Emanuele Giaquinta <e.giaquinta@glauco.it>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 3 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *---------------------------------------------------------------------*/
32 /*
33 * Initialisation routines.
34 */
35
36 #include "../config.h" /* NECESSARY */
37 #include "rxvt.h" /* NECESSARY */
38 #include "rxvtutil.h"
39 #include "init.h"
40 #include "keyboard.h"
41
42 #include <limits>
43
44 #include <signal.h>
45
46 #include <fcntl.h>
47
48 #ifdef HAVE_XMU
49 # include <X11/Xmu/CurUtil.h>
50 #endif
51
52 #ifdef HAVE_XSETLOCALE
53 # define X_LOCALE
54 # include <X11/Xlocale.h>
55 #else
56 # include <locale.h>
57 #endif
58
59 #ifdef HAVE_NL_LANGINFO
60 # include <langinfo.h>
61 #endif
62
63 #ifdef HAVE_STARTUP_NOTIFICATION
64 # define SN_API_NOT_YET_FROZEN
65 # include <libsn/sn-launchee.h>
66 #endif
67
68 #ifdef DISPLAY_IS_IP
69 /* On Solaris link with -lsocket and -lnsl */
70 #include <sys/types.h>
71 #include <sys/socket.h>
72
73 /* these next two are probably only on Sun (not Solaris) */
74 #ifdef HAVE_SYS_SOCKIO_H
75 #include <sys/sockio.h>
76 #endif
77 #ifdef HAVE_SYS_BYTEORDER_H
78 #include <sys/byteorder.h>
79 #endif
80
81 #include <netinet/in.h>
82 #include <arpa/inet.h>
83 #include <net/if.h>
84 #include <net/if_arp.h>
85
86 static char * ecb_cold
87 rxvt_network_display (const char *display)
88 {
89 char buffer[1024], *rval = NULL;
90 struct ifconf ifc;
91 struct ifreq *ifr;
92 int i, skfd;
93
94 if (display[0] != ':' && strncmp (display, "unix:", 5))
95 return (char *) display; /* nothing to do */
96
97 ifc.ifc_len = sizeof (buffer); /* Get names of all ifaces */
98 ifc.ifc_buf = buffer;
99
100 if ((skfd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
101 {
102 perror ("socket");
103 return NULL;
104 }
105
106 if (ioctl (skfd, SIOCGIFCONF, &ifc) < 0)
107 {
108 perror ("SIOCGIFCONF");
109 close (skfd);
110 return NULL;
111 }
112
113 for (i = 0, ifr = ifc.ifc_req;
114 i < (ifc.ifc_len / sizeof (struct ifreq));
115 i++, ifr++)
116 {
117 struct ifreq ifr2;
118
119 strcpy (ifr2.ifr_name, ifr->ifr_name);
120
121 if (ioctl (skfd, SIOCGIFADDR, &ifr2) >= 0)
122 {
123 unsigned long addr;
124 struct sockaddr_in *p_addr;
125
126 p_addr = (struct sockaddr_in *) &ifr2.ifr_addr;
127 addr = htonl ((unsigned long)p_addr->sin_addr.s_addr);
128
129 /*
130 * not "0.0.0.0" or "127.0.0.1" - so format the address
131 */
132 if (addr && addr != 0x7F000001)
133 {
134 char *colon = strchr (display, ':');
135
136 if (colon == NULL)
137 colon = ":0.0";
138
139 rval = rxvt_malloc (strlen (colon) + 16);
140 sprintf (rval, "%d.%d.%d.%d%s",
141 (int) ((addr >> 030) & 0xFF),
142 (int) ((addr >> 020) & 0xFF),
143 (int) ((addr >> 010) & 0xFF),
144 (int) (addr & 0xFF), colon);
145 break;
146 }
147 }
148 }
149
150 close (skfd);
151
152 return rval;
153 }
154 #endif
155
156 #define NULL_5 \
157 NULL, \
158 NULL, \
159 NULL, \
160 NULL, \
161 NULL,
162
163 #define NULL_10 \
164 NULL_5 \
165 NULL_5
166
167 #define NULL_40 \
168 NULL_10 \
169 NULL_10 \
170 NULL_10 \
171 NULL_10
172
173 #define NULL_50 \
174 NULL_40 \
175 NULL_10
176
177 #define NULL_100 \
178 NULL_50 \
179 NULL_50
180
181 static const char *const def_colorName[] =
182 {
183 COLOR_FOREGROUND,
184 COLOR_BACKGROUND,
185 /* low-intensity colors */
186 "rgb:00/00/00", // 0: black (Black)
187 "rgb:cd/00/00", // 1: red (Red3)
188 "rgb:00/cd/00", // 2: green (Green3)
189 "rgb:cd/cd/00", // 3: yellow (Yellow3)
190 "rgb:00/00/cd", // 4: blue (Blue3)
191 "rgb:cd/00/cd", // 5: magenta (Magenta3)
192 "rgb:00/cd/cd", // 6: cyan (Cyan3)
193 # ifdef XTERM_COLORS
194 "rgb:e5/e5/e5", // 7: white (Grey90)
195 # else
196 "rgb:fa/eb/d7", // 7: white (AntiqueWhite)
197 # endif
198 /* high-intensity colors */
199 # ifdef XTERM_COLORS
200 "rgb:4d/4d/4d", // 8: bright black (Grey30)
201 # else
202 "rgb:40/40/40", // 8: bright black (Grey25)
203 # endif
204 "rgb:ff/00/00", // 1/9: bright red (Reed)
205 "rgb:00/ff/00", // 2/10: bright green (Green)
206 "rgb:ff/ff/00", // 3/11: bright yellow (Yellow)
207 "rgb:00/00/ff", // 4/12: bright blue (Blue)
208 "rgb:ff/00/ff", // 5/13: bright magenta (Magenta)
209 "rgb:00/ff/ff", // 6/14: bright cyan (Cyan)
210 "rgb:ff/ff/ff", // 7/15: bright white (White)
211
212 #if !USE_256_COLORS
213 // 88 xterm colours
214 "rgb:00/00/00",
215 "rgb:00/00/8b",
216 "rgb:00/00/cd",
217 "rgb:00/00/ff",
218 "rgb:00/8b/00",
219 "rgb:00/8b/8b",
220 "rgb:00/8b/cd",
221 "rgb:00/8b/ff",
222 "rgb:00/cd/00",
223 "rgb:00/cd/8b",
224 "rgb:00/cd/cd",
225 "rgb:00/cd/ff",
226 "rgb:00/ff/00",
227 "rgb:00/ff/8b",
228 "rgb:00/ff/cd",
229 "rgb:00/ff/ff",
230 "rgb:8b/00/00",
231 "rgb:8b/00/8b",
232 "rgb:8b/00/cd",
233 "rgb:8b/00/ff",
234 "rgb:8b/8b/00",
235 "rgb:8b/8b/8b",
236 "rgb:8b/8b/cd",
237 "rgb:8b/8b/ff",
238 "rgb:8b/cd/00",
239 "rgb:8b/cd/8b",
240 "rgb:8b/cd/cd",
241 "rgb:8b/cd/ff",
242 "rgb:8b/ff/00",
243 "rgb:8b/ff/8b",
244 "rgb:8b/ff/cd",
245 "rgb:8b/ff/ff",
246 "rgb:cd/00/00",
247 "rgb:cd/00/8b",
248 "rgb:cd/00/cd",
249 "rgb:cd/00/ff",
250 "rgb:cd/8b/00",
251 "rgb:cd/8b/8b",
252 "rgb:cd/8b/cd",
253 "rgb:cd/8b/ff",
254 "rgb:cd/cd/00",
255 "rgb:cd/cd/8b",
256 "rgb:cd/cd/cd",
257 "rgb:cd/cd/ff",
258 "rgb:cd/ff/00",
259 "rgb:cd/ff/8b",
260 "rgb:cd/ff/cd",
261 "rgb:cd/ff/ff",
262 "rgb:ff/00/00",
263 "rgb:ff/00/8b",
264 "rgb:ff/00/cd",
265 "rgb:ff/00/ff",
266 "rgb:ff/8b/00",
267 "rgb:ff/8b/8b",
268 "rgb:ff/8b/cd",
269 "rgb:ff/8b/ff",
270 "rgb:ff/cd/00",
271 "rgb:ff/cd/8b",
272 "rgb:ff/cd/cd",
273 "rgb:ff/cd/ff",
274 "rgb:ff/ff/00",
275 "rgb:ff/ff/8b",
276 "rgb:ff/ff/cd",
277 "rgb:ff/ff/ff",
278 "rgb:2e/2e/2e",
279 "rgb:5c/5c/5c",
280 "rgb:73/73/73",
281 "rgb:8b/8b/8b",
282 "rgb:a2/a2/a2",
283 "rgb:b9/b9/b9",
284 "rgb:d0/d0/d0",
285 "rgb:e7/e7/e7",
286 NULL_100
287 NULL_40
288 NULL,
289 NULL,
290 NULL,
291 NULL,
292 #else
293 // 256 xterm colours
294 "rgb:00/00/00",
295 "rgb:00/00/5f",
296 "rgb:00/00/87",
297 "rgb:00/00/af",
298 "rgb:00/00/d7",
299 "rgb:00/00/ff",
300 "rgb:00/5f/00",
301 "rgb:00/5f/5f",
302 "rgb:00/5f/87",
303 "rgb:00/5f/af",
304 "rgb:00/5f/d7",
305 "rgb:00/5f/ff",
306 "rgb:00/87/00",
307 "rgb:00/87/5f",
308 "rgb:00/87/87",
309 "rgb:00/87/af",
310 "rgb:00/87/d7",
311 "rgb:00/87/ff",
312 "rgb:00/af/00",
313 "rgb:00/af/5f",
314 "rgb:00/af/87",
315 "rgb:00/af/af",
316 "rgb:00/af/d7",
317 "rgb:00/af/ff",
318 "rgb:00/d7/00",
319 "rgb:00/d7/5f",
320 "rgb:00/d7/87",
321 "rgb:00/d7/af",
322 "rgb:00/d7/d7",
323 "rgb:00/d7/ff",
324 "rgb:00/ff/00",
325 "rgb:00/ff/5f",
326 "rgb:00/ff/87",
327 "rgb:00/ff/af",
328 "rgb:00/ff/d7",
329 "rgb:00/ff/ff",
330 "rgb:5f/00/00",
331 "rgb:5f/00/5f",
332 "rgb:5f/00/87",
333 "rgb:5f/00/af",
334 "rgb:5f/00/d7",
335 "rgb:5f/00/ff",
336 "rgb:5f/5f/00",
337 "rgb:5f/5f/5f",
338 "rgb:5f/5f/87",
339 "rgb:5f/5f/af",
340 "rgb:5f/5f/d7",
341 "rgb:5f/5f/ff",
342 "rgb:5f/87/00",
343 "rgb:5f/87/5f",
344 "rgb:5f/87/87",
345 "rgb:5f/87/af",
346 "rgb:5f/87/d7",
347 "rgb:5f/87/ff",
348 "rgb:5f/af/00",
349 "rgb:5f/af/5f",
350 "rgb:5f/af/87",
351 "rgb:5f/af/af",
352 "rgb:5f/af/d7",
353 "rgb:5f/af/ff",
354 "rgb:5f/d7/00",
355 "rgb:5f/d7/5f",
356 "rgb:5f/d7/87",
357 "rgb:5f/d7/af",
358 "rgb:5f/d7/d7",
359 "rgb:5f/d7/ff",
360 "rgb:5f/ff/00",
361 "rgb:5f/ff/5f",
362 "rgb:5f/ff/87",
363 "rgb:5f/ff/af",
364 "rgb:5f/ff/d7",
365 "rgb:5f/ff/ff",
366 "rgb:87/00/00",
367 "rgb:87/00/5f",
368 "rgb:87/00/87",
369 "rgb:87/00/af",
370 "rgb:87/00/d7",
371 "rgb:87/00/ff",
372 "rgb:87/5f/00",
373 "rgb:87/5f/5f",
374 "rgb:87/5f/87",
375 "rgb:87/5f/af",
376 "rgb:87/5f/d7",
377 "rgb:87/5f/ff",
378 "rgb:87/87/00",
379 "rgb:87/87/5f",
380 "rgb:87/87/87",
381 "rgb:87/87/af",
382 "rgb:87/87/d7",
383 "rgb:87/87/ff",
384 "rgb:87/af/00",
385 "rgb:87/af/5f",
386 "rgb:87/af/87",
387 "rgb:87/af/af",
388 "rgb:87/af/d7",
389 "rgb:87/af/ff",
390 "rgb:87/d7/00",
391 "rgb:87/d7/5f",
392 "rgb:87/d7/87",
393 "rgb:87/d7/af",
394 "rgb:87/d7/d7",
395 "rgb:87/d7/ff",
396 "rgb:87/ff/00",
397 "rgb:87/ff/5f",
398 "rgb:87/ff/87",
399 "rgb:87/ff/af",
400 "rgb:87/ff/d7",
401 "rgb:87/ff/ff",
402 "rgb:af/00/00",
403 "rgb:af/00/5f",
404 "rgb:af/00/87",
405 "rgb:af/00/af",
406 "rgb:af/00/d7",
407 "rgb:af/00/ff",
408 "rgb:af/5f/00",
409 "rgb:af/5f/5f",
410 "rgb:af/5f/87",
411 "rgb:af/5f/af",
412 "rgb:af/5f/d7",
413 "rgb:af/5f/ff",
414 "rgb:af/87/00",
415 "rgb:af/87/5f",
416 "rgb:af/87/87",
417 "rgb:af/87/af",
418 "rgb:af/87/d7",
419 "rgb:af/87/ff",
420 "rgb:af/af/00",
421 "rgb:af/af/5f",
422 "rgb:af/af/87",
423 "rgb:af/af/af",
424 "rgb:af/af/d7",
425 "rgb:af/af/ff",
426 "rgb:af/d7/00",
427 "rgb:af/d7/5f",
428 "rgb:af/d7/87",
429 "rgb:af/d7/af",
430 "rgb:af/d7/d7",
431 "rgb:af/d7/ff",
432 "rgb:af/ff/00",
433 "rgb:af/ff/5f",
434 "rgb:af/ff/87",
435 "rgb:af/ff/af",
436 "rgb:af/ff/d7",
437 "rgb:af/ff/ff",
438 "rgb:d7/00/00",
439 "rgb:d7/00/5f",
440 "rgb:d7/00/87",
441 "rgb:d7/00/af",
442 "rgb:d7/00/d7",
443 "rgb:d7/00/ff",
444 "rgb:d7/5f/00",
445 "rgb:d7/5f/5f",
446 "rgb:d7/5f/87",
447 "rgb:d7/5f/af",
448 "rgb:d7/5f/d7",
449 "rgb:d7/5f/ff",
450 "rgb:d7/87/00",
451 "rgb:d7/87/5f",
452 "rgb:d7/87/87",
453 "rgb:d7/87/af",
454 "rgb:d7/87/d7",
455 "rgb:d7/87/ff",
456 "rgb:d7/af/00",
457 "rgb:d7/af/5f",
458 "rgb:d7/af/87",
459 "rgb:d7/af/af",
460 "rgb:d7/af/d7",
461 "rgb:d7/af/ff",
462 "rgb:d7/d7/00",
463 "rgb:d7/d7/5f",
464 "rgb:d7/d7/87",
465 "rgb:d7/d7/af",
466 "rgb:d7/d7/d7",
467 "rgb:d7/d7/ff",
468 "rgb:d7/ff/00",
469 "rgb:d7/ff/5f",
470 "rgb:d7/ff/87",
471 "rgb:d7/ff/af",
472 "rgb:d7/ff/d7",
473 "rgb:d7/ff/ff",
474 "rgb:ff/00/00",
475 "rgb:ff/00/5f",
476 "rgb:ff/00/87",
477 "rgb:ff/00/af",
478 "rgb:ff/00/d7",
479 "rgb:ff/00/ff",
480 "rgb:ff/5f/00",
481 "rgb:ff/5f/5f",
482 "rgb:ff/5f/87",
483 "rgb:ff/5f/af",
484 "rgb:ff/5f/d7",
485 "rgb:ff/5f/ff",
486 "rgb:ff/87/00",
487 "rgb:ff/87/5f",
488 "rgb:ff/87/87",
489 "rgb:ff/87/af",
490 "rgb:ff/87/d7",
491 "rgb:ff/87/ff",
492 "rgb:ff/af/00",
493 "rgb:ff/af/5f",
494 "rgb:ff/af/87",
495 "rgb:ff/af/af",
496 "rgb:ff/af/d7",
497 "rgb:ff/af/ff",
498 "rgb:ff/d7/00",
499 "rgb:ff/d7/5f",
500 "rgb:ff/d7/87",
501 "rgb:ff/d7/af",
502 "rgb:ff/d7/d7",
503 "rgb:ff/d7/ff",
504 "rgb:ff/ff/00",
505 "rgb:ff/ff/5f",
506 "rgb:ff/ff/87",
507 "rgb:ff/ff/af",
508 "rgb:ff/ff/d7",
509 "rgb:ff/ff/ff",
510 "rgb:08/08/08",
511 "rgb:12/12/12",
512 "rgb:1c/1c/1c",
513 "rgb:26/26/26",
514 "rgb:30/30/30",
515 "rgb:3a/3a/3a",
516 "rgb:44/44/44",
517 "rgb:4e/4e/4e",
518 "rgb:58/58/58",
519 "rgb:62/62/62",
520 "rgb:6c/6c/6c",
521 "rgb:76/76/76",
522 "rgb:80/80/80",
523 "rgb:8a/8a/8a",
524 "rgb:94/94/94",
525 "rgb:9e/9e/9e",
526 "rgb:a8/a8/a8",
527 "rgb:b2/b2/b2",
528 "rgb:bc/bc/bc",
529 "rgb:c6/c6/c6",
530 "rgb:d0/d0/d0",
531 "rgb:da/da/da",
532 "rgb:e4/e4/e4",
533 "rgb:ee/ee/ee",
534 NULL_100
535 NULL_100
536 NULL_40
537 NULL_5
538 #endif
539
540 #ifndef NO_CURSORCOLOR
541 COLOR_CURSOR_BACKGROUND,
542 COLOR_CURSOR_FOREGROUND,
543 #endif /* ! NO_CURSORCOLOR */
544 NULL, /* Color_pointer_fg */
545 NULL, /* Color_pointer_bg */
546 NULL, /* Color_border */
547 #ifndef NO_BOLD_UNDERLINE_REVERSE
548 NULL, /* Color_BD */
549 NULL, /* Color_IT */
550 NULL, /* Color_UL */
551 NULL, /* Color_RV */
552 #endif /* ! NO_BOLD_UNDERLINE_REVERSE */
553 #if ENABLE_FRILLS
554 NULL, // Color_underline
555 #endif
556 #ifdef OPTION_HC
557 NULL,
558 NULL,
559 #endif
560 COLOR_SCROLLBAR,
561 #ifdef RXVT_SCROLLBAR
562 COLOR_SCROLLTROUGH,
563 #endif
564 #if BG_IMAGE_FROM_ROOT
565 NULL,
566 #endif
567 #if OFF_FOCUS_FADING
568 "rgb:00/00/00",
569 #endif
570 };
571
572 void
573 rxvt_term::init_vars ()
574 {
575 pix_colors = pix_colors_focused;
576
577 MEvent.time = CurrentTime;
578 MEvent.button = AnyButton;
579 want_refresh = 1;
580 priv_modes = SavedModes = PrivMode_Default;
581 ncol = 80;
582 nrow = 24;
583 int_bwidth = INTERNALBORDERWIDTH;
584 ext_bwidth = EXTERNALBORDERWIDTH;
585 lineSpace = LINESPACE;
586 letterSpace = LETTERSPACE;
587 saveLines = SAVELINES;
588
589 refresh_type = SLOW_REFRESH;
590
591 oldcursor.row = oldcursor.col = -1;
592
593 set_option (Opt_scrollBar);
594 set_option (Opt_scrollTtyOutput);
595 set_option (Opt_jumpScroll);
596 set_option (Opt_skipScroll);
597 set_option (Opt_secondaryScreen);
598 set_option (Opt_secondaryScroll);
599 set_option (Opt_pastableTabs);
600 set_option (Opt_intensityStyles);
601 set_option (Opt_iso14755);
602 set_option (Opt_iso14755_52);
603 set_option (Opt_buffered);
604 }
605
606 /*----------------------------------------------------------------------*/
607 const char **
608 rxvt_term::init_resources (int argc, const char *const *argv)
609 {
610 int i;
611 const char **cmd_argv;
612
613 rs[Rs_name] = rxvt_basename (argv[0]);
614
615 /*
616 * Open display, get options/resources and create the window
617 */
618
619 if ((rs[Rs_display_name] = getenv ("DISPLAY")) == NULL)
620 rs[Rs_display_name] = ":0";
621
622 cmd_argv = get_options (argc, argv);
623
624 if (!(display = displays.get (rs[Rs_display_name])))
625 rxvt_fatal ("can't open display %s, aborting.\n", rs[Rs_display_name]);
626
627 // using a local pointer decreases code size a lot
628 xa = display->xa;
629
630 set (display);
631 extract_resources ();
632
633 #if ENABLE_FRILLS
634 if (rs[Rs_visual])
635 select_visual (strtol (rs[Rs_visual], 0, 0));
636 else if (rs[Rs_depth])
637 select_depth (strtol (rs[Rs_depth], 0, 0));
638 #endif
639
640 for (int i = NUM_RESOURCES; i--; )
641 if (rs [i] == resval_undef)
642 rs [i] = 0;
643
644 #if ENABLE_PERL
645 if (!rs[Rs_perl_ext_1])
646 rs[Rs_perl_ext_1] = "default";
647
648 if ((rs[Rs_perl_ext_1] && *rs[Rs_perl_ext_1])
649 || (rs[Rs_perl_ext_2] && *rs[Rs_perl_ext_2])
650 || (rs[Rs_perl_eval] && *rs[Rs_perl_eval]))
651 {
652 rxvt_perl.init (this);
653 HOOK_INVOKE ((this, HOOK_INIT, DT_END));
654 }
655 #endif
656
657 // must be called after initialising the perl interpreter as it
658 // may invoke the `on_register_command' hook
659 extract_keysym_resources ();
660
661 /*
662 * set any defaults not already set
663 */
664 if (cmd_argv && cmd_argv[0])
665 {
666 if (!rs[Rs_title])
667 rs[Rs_title] = rxvt_basename (cmd_argv[0]);
668
669 if (!rs[Rs_iconName])
670 rs[Rs_iconName] = rs[Rs_title];
671 }
672 else
673 {
674 if (!rs[Rs_title])
675 rs[Rs_title] = rs[Rs_name];
676
677 if (!rs[Rs_iconName])
678 rs[Rs_iconName] = rs[Rs_name];
679 }
680
681 if (rs[Rs_saveLines] && (i = atoi (rs[Rs_saveLines])) >= 0)
682 saveLines = min (i, MAX_SAVELINES);
683
684 #if ENABLE_FRILLS
685 if (rs[Rs_int_bwidth] && (i = atoi (rs[Rs_int_bwidth])) >= 0)
686 int_bwidth = min (i, std::numeric_limits<int16_t>::max ());
687
688 if (rs[Rs_ext_bwidth] && (i = atoi (rs[Rs_ext_bwidth])) >= 0)
689 ext_bwidth = min (i, std::numeric_limits<int16_t>::max ());
690
691 if (rs[Rs_lineSpace] && (i = atoi (rs[Rs_lineSpace])) >= 0)
692 lineSpace = min (i, std::numeric_limits<int16_t>::max ());
693
694 if (rs[Rs_letterSpace])
695 letterSpace = atoi (rs[Rs_letterSpace]);
696 #endif
697
698 #ifdef POINTER_BLANK
699 if (rs[Rs_pointerBlankDelay] && (i = atoi (rs[Rs_pointerBlankDelay])) >= 0)
700 pointerBlankDelay = i;
701 else
702 pointerBlankDelay = 2;
703 #endif
704
705 if (rs[Rs_multiClickTime] && (i = atoi (rs[Rs_multiClickTime])) >= 0)
706 multiClickTime = i;
707 else
708 multiClickTime = 500;
709
710 cursor_type = option (Opt_cursorUnderline) ? 1 : 0;
711
712 /* no point having a scrollbar without having any scrollback! */
713 if (!saveLines)
714 set_option (Opt_scrollBar, 0);
715
716 if (!rs[Rs_cutchars])
717 rs[Rs_cutchars] = CUTCHARS;
718
719 #ifndef NO_BACKSPACE_KEY
720 if (!rs[Rs_backspace_key])
721 # ifdef DEFAULT_BACKSPACE
722 rs[Rs_backspace_key] = DEFAULT_BACKSPACE;
723 # else
724 rs[Rs_backspace_key] = "DEC"; /* can toggle between \010 or \177 */
725 # endif
726 #endif
727
728 #ifndef NO_DELETE_KEY
729 if (!rs[Rs_delete_key])
730 # ifdef DEFAULT_DELETE
731 rs[Rs_delete_key] = DEFAULT_DELETE;
732 # else
733 rs[Rs_delete_key] = "\033[3~";
734 # endif
735 #endif
736
737 scrollBar.setup (this);
738
739 #ifdef XTERM_REVERSE_VIDEO
740 /* this is how xterm implements reverseVideo */
741 if (option (Opt_reverseVideo))
742 {
743 if (!rs[Rs_color + Color_fg])
744 rs[Rs_color + Color_fg] = def_colorName[Color_bg];
745
746 if (!rs[Rs_color + Color_bg])
747 rs[Rs_color + Color_bg] = def_colorName[Color_fg];
748 }
749 #endif
750
751 for (i = 0; i < NRS_COLORS; i++)
752 if (!rs[Rs_color + i])
753 rs[Rs_color + i] = def_colorName[i];
754
755 #ifndef XTERM_REVERSE_VIDEO
756 /* this is how we implement reverseVideo */
757 if (option (Opt_reverseVideo))
758 ::swap (rs[Rs_color + Color_fg], rs[Rs_color + Color_bg]);
759 #endif
760
761 /* convenient aliases for setting fg/bg to colors */
762 color_aliases (Color_fg);
763 color_aliases (Color_bg);
764 #ifndef NO_CURSORCOLOR
765 color_aliases (Color_cursor);
766 color_aliases (Color_cursor2);
767 #endif /* NO_CURSORCOLOR */
768 color_aliases (Color_pointer_fg);
769 color_aliases (Color_pointer_bg);
770 color_aliases (Color_border);
771 #ifndef NO_BOLD_UNDERLINE_REVERSE
772 color_aliases (Color_BD);
773 color_aliases (Color_UL);
774 color_aliases (Color_RV);
775 #endif /* ! NO_BOLD_UNDERLINE_REVERSE */
776
777 if (!rs[Rs_color + Color_border])
778 rs[Rs_color + Color_border] = rs[Rs_color + Color_bg];
779
780 return cmd_argv;
781 }
782
783 /*----------------------------------------------------------------------*/
784 void
785 rxvt_term::init (stringvec *argv, stringvec *envv)
786 {
787 argv->push_back (0);
788 envv->push_back (0);
789
790 this->argv = argv;
791 this->envv = envv;
792
793 env = new char *[this->envv->size ()];
794 for (int i = 0; i < this->envv->size (); i++)
795 env[i] = this->envv->at (i);
796
797 init2 (argv->size () - 1, argv->begin ());
798 }
799
800 void
801 rxvt_term::init (int argc, const char *const *argv, const char *const *envv)
802 {
803 #if ENABLE_PERL
804 // perl might want to access the stringvecs later, so we need to copy them
805 stringvec *args = new stringvec;
806 for (int i = 0; i < argc; i++)
807 args->push_back (strdup (argv [i]));
808
809 stringvec *envs = new stringvec;
810 for (const char *const *var = envv; *var; var++)
811 envs->push_back (strdup (*var));
812
813 init (args, envs);
814 #else
815 init2 (argc, argv);
816 #endif
817 }
818
819 void
820 rxvt_term::init2 (int argc, const char *const *argv)
821 {
822 SET_R (this);
823 set_locale ("");
824 set_environ (env); // a few things in X do not call setlocale :(
825
826 init_vars ();
827
828 const char **cmd_argv = init_resources (argc, argv);
829
830 #ifdef KEYSYM_RESOURCE
831 keyboard->register_done ();
832 #endif
833
834 if (const char *path = rs[Rs_chdir])
835 if (*path) // ignored if empty
836 {
837 if (*path != '/')
838 rxvt_fatal ("specified shell working directory must start with a slash, aborting.\n");
839
840 if (chdir (path))
841 rxvt_fatal ("unable to change into specified shell working directory, aborting.\n");
842 }
843
844 if (option (Opt_scrollBar))
845 scrollBar.state = SB_STATE_IDLE; /* set existence for size calculations */
846
847 pty = ptytty::create ();
848
849 create_windows (argc, argv);
850
851 init_xlocale ();
852
853 scr_poweron (); // initialize screen
854
855 #if 0
856 XSynchronize (dpy, True);
857 #endif
858
859 if (option (Opt_scrollBar))
860 scrollBar.resize (); /* create and map scrollbar */
861
862 #ifdef HAVE_BG_PIXMAP
863 bg_init ();
864 #endif
865
866 #if ENABLE_PERL
867 rootwin_ev.start (display, display->root);
868 #endif
869
870 init_done = 1;
871
872 init_command (cmd_argv);
873
874 if (pty->pty >= 0)
875 pty_ev.start (pty->pty, ev::READ);
876
877 HOOK_INVOKE ((this, HOOK_START, DT_END));
878
879 #if ENABLE_XEMBED
880 if (rs[Rs_embed])
881 {
882 long info[2] = { 0, XEMBED_MAPPED };
883
884 XChangeProperty (dpy, parent, xa[XA_XEMBED_INFO], xa[XA_XEMBED_INFO],
885 32, PropModeReplace, (unsigned char *)&info, 2);
886 }
887 #endif
888
889 #if HAVE_STARTUP_NOTIFICATION
890 SnDisplay *snDisplay;
891 SnLauncheeContext *snContext;
892
893 snDisplay = sn_display_new (dpy, NULL, NULL);
894 snContext = sn_launchee_context_new_from_environment (snDisplay, DefaultScreen (dpy));
895
896 /* Tell the window manager that this window is part of the startup context */
897 if (snContext)
898 sn_launchee_context_setup_window (snContext, parent);
899 #endif
900
901 XMapWindow (dpy, vt);
902 XMapWindow (dpy, parent);
903
904 #if HAVE_STARTUP_NOTIFICATION
905 if (snContext)
906 {
907 /* Mark the startup process as complete */
908 sn_launchee_context_complete (snContext);
909
910 sn_launchee_context_unref (snContext);
911 }
912
913 sn_display_unref (snDisplay);
914 #endif
915
916 refresh_check ();
917 }
918
919 /*----------------------------------------------------------------------*/
920 void
921 rxvt_term::init_env ()
922 {
923 char *val;
924 char *env_display;
925 char *env_windowid;
926 char *env_colorfgbg;
927 char *env_term;
928
929 #ifdef DISPLAY_IS_IP
930 /* Fixup display_name for export over pty to any interested terminal
931 * clients via "ESC[7n" (e.g. shells). Note we use the pure IP number
932 * (for the first non-loopback interface) that we get from
933 * rxvt_network_display (). This is more "name-resolution-portable", if you
934 * will, and probably allows for faster x-client startup if your name
935 * server is beyond a slow link or overloaded at client startup. Of
936 * course that only helps the shell's child processes, not us.
937 *
938 * Giving out the display_name also affords a potential security hole
939 */
940 val = rxvt_network_display (rs[Rs_display_name]);
941 rs[Rs_display_name] = (const char *)val;
942
943 if (val == NULL)
944 #endif /* DISPLAY_IS_IP */
945 val = XDisplayString (dpy);
946
947 if (rs[Rs_display_name] == NULL)
948 rs[Rs_display_name] = val; /* use broken `:0' value */
949
950 env_display = (char *)rxvt_malloc (strlen (val) + 9);
951
952 sprintf (env_display, "DISPLAY=%s", val);
953
954 env_windowid = (char *)rxvt_malloc (21);
955 sprintf (env_windowid, "WINDOWID=%lu", (unsigned long)parent);
956
957 /* add entries to the environment:
958 * @ DISPLAY: in case we started with -display
959 * @ WINDOWID: X window id number of the window
960 * @ COLORTERM: terminal sub-name and also indicates its color
961 * @ TERM: terminal name
962 * @ TERMINFO: path to terminfo directory
963 * @ COLORFGBG: fg;bg color codes
964 */
965 putenv (env_display);
966 putenv (env_windowid);
967
968 env_colorfgbg = get_colorfgbg ();
969 putenv (env_colorfgbg);
970
971 #ifdef RXVT_TERMINFO
972 putenv ("TERMINFO=" RXVT_TERMINFO);
973 #endif
974
975 if (depth <= 2)
976 putenv ("COLORTERM=" COLORTERMENV "-mono");
977 else
978 putenv ("COLORTERM=" COLORTERMENVFULL);
979
980 if (rs[Rs_term_name] != NULL)
981 {
982 env_term = (char *)rxvt_malloc (strlen (rs[Rs_term_name]) + 6);
983 sprintf (env_term, "TERM=%s", rs[Rs_term_name]);
984 putenv (env_term);
985 }
986 else
987 putenv ("TERM=" TERMENV);
988
989 #ifdef HAVE_UNSETENV
990 /* avoid passing old settings and confusing term size */
991 unsetenv ("LINES");
992 unsetenv ("COLUMNS");
993 unsetenv ("TERMCAP"); /* terminfo should be okay */
994 #endif /* HAVE_UNSETENV */
995 }
996
997 /*----------------------------------------------------------------------*/
998 void
999 rxvt_term::set_locale (const char *locale)
1000 {
1001 set_environ (env);
1002
1003 free (this->locale);
1004 this->locale = setlocale (LC_CTYPE, locale);
1005
1006 if (!this->locale)
1007 {
1008 if (*locale)
1009 {
1010 rxvt_warn ("unable to set locale \"%s\", using C locale instead.\n", locale);
1011 setlocale (LC_CTYPE, "C");
1012 }
1013 else
1014 rxvt_warn ("default locale unavailable, check LC_* and LANG variables. Continuing.\n");
1015
1016 this->locale = "C";
1017 }
1018
1019
1020 this->locale = strdup (this->locale);
1021 SET_LOCALE (this->locale);
1022 mbstate.reset ();
1023
1024 #if HAVE_NL_LANGINFO
1025 char *codeset = nl_langinfo (CODESET);
1026 // /^UTF.?8/i
1027 enc_utf8 = (codeset[0] == 'U' || codeset[0] == 'u')
1028 && (codeset[1] == 'T' || codeset[1] == 't')
1029 && (codeset[2] == 'F' || codeset[2] == 'f')
1030 && (codeset[3] == '8' || codeset[4] == '8');
1031 #else
1032 enc_utf8 = 0;
1033 #endif
1034 }
1035
1036 void
1037 rxvt_term::init_xlocale ()
1038 {
1039 set_environ (env);
1040
1041 #if USE_XIM
1042 if (!locale)
1043 rxvt_warn ("setting locale failed, continuing without locale support.\n");
1044 else
1045 {
1046 set_string_property (xa[XA_WM_LOCALE_NAME], locale);
1047
1048 if (!XSupportsLocale ())
1049 {
1050 rxvt_warn ("the locale is not supported by Xlib, continuing without locale support.\n");
1051 return;
1052 }
1053
1054 im_ev.start (display);
1055
1056 /* see if we can connect already */
1057 im_cb ();
1058 }
1059 #endif
1060 }
1061
1062 /*----------------------------------------------------------------------*/
1063 void
1064 rxvt_term::init_command (const char *const *argv)
1065 {
1066 /*
1067 * Initialize the command connection.
1068 * This should be called after the X server connection is established.
1069 */
1070
1071 #ifdef META8_OPTION
1072 meta_char = option (Opt_meta8) ? 0x80 : C0_ESC;
1073 #endif
1074
1075 get_ourmods ();
1076
1077 if (!option (Opt_scrollTtyOutput))
1078 priv_modes |= PrivMode_TtyOutputInh;
1079 if (option (Opt_scrollTtyKeypress))
1080 priv_modes |= PrivMode_Keypress;
1081 if (!option (Opt_jumpScroll))
1082 priv_modes |= PrivMode_smoothScroll;
1083
1084 #ifndef NO_BACKSPACE_KEY
1085 if (strcmp (rs[Rs_backspace_key], "DEC") == 0)
1086 priv_modes |= PrivMode_HaveBackSpace;
1087 #endif
1088
1089 /* add value for scrollBar */
1090 if (scrollBar.state)
1091 {
1092 priv_modes |= PrivMode_scrollBar;
1093 SavedModes |= PrivMode_scrollBar;
1094 }
1095
1096 run_command (argv);
1097 }
1098
1099 /*----------------------------------------------------------------------*/
1100 void
1101 rxvt_term::get_colors ()
1102 {
1103 int i;
1104
1105 #ifdef OFF_FOCUS_FADING
1106 pix_colors = pix_colors_focused;
1107 #endif
1108
1109 for (i = 0; i < NRS_COLORS; i++)
1110 if (const char *name = rs[Rs_color + i])
1111 set_color (pix_colors [i], name);
1112
1113 /*
1114 * get scrollBar shadow colors
1115 *
1116 * The calculations of topShadow/bottomShadow values are adapted
1117 * from the fvwm window manager.
1118 */
1119 #ifdef RXVT_SCROLLBAR
1120 pix_colors [Color_scroll].fade (this, 50, pix_colors [Color_bottomShadow]);
1121
1122 rgba cscroll;
1123 pix_colors [Color_scroll].get (cscroll);
1124
1125 /* topShadowColor */
1126 if (!pix_colors[Color_topShadow].set (this,
1127 rgba (
1128 min ((int)rgba::MAX_CC, max (cscroll.r / 5, cscroll.r) * 7 / 5),
1129 min ((int)rgba::MAX_CC, max (cscroll.g / 5, cscroll.g) * 7 / 5),
1130 min ((int)rgba::MAX_CC, max (cscroll.b / 5, cscroll.b) * 7 / 5),
1131 cscroll.a)
1132 ))
1133 alias_color (Color_topShadow, Color_White);
1134 #endif
1135
1136 #ifdef OFF_FOCUS_FADING
1137 for (i = 0; i < NRS_COLORS; i++)
1138 update_fade_color (i, true);
1139 #endif
1140 }
1141
1142 /*----------------------------------------------------------------------*/
1143 /* color aliases, fg/bg bright-bold */
1144 void
1145 rxvt_term::color_aliases (int idx)
1146 {
1147 if (rs[Rs_color + idx] && isdigit (*rs[Rs_color + idx]))
1148 {
1149 int i = atoi (rs[Rs_color + idx]);
1150
1151 if (i >= 8 && i <= 15)
1152 /* bright colors */
1153 rs[Rs_color + idx] = rs[Rs_color + minBrightCOLOR + i - 8];
1154 else if (i >= 0 && i <= 7)
1155 /* normal colors */
1156 rs[Rs_color + idx] = rs[Rs_color + minCOLOR + i];
1157 }
1158 }
1159
1160 /*----------------------------------------------------------------------*/
1161 /*
1162 * Probe the modifier keymap to get the Meta (Alt) and Num_Lock settings
1163 * Use resource ``modifier'' to override the Meta modifier
1164 */
1165 void
1166 rxvt_term::get_ourmods ()
1167 {
1168 int i, j, k;
1169 int requestedmeta, realmeta, realalt;
1170 const char *cm, *rsmod;
1171 XModifierKeymap *map;
1172 KeyCode *kc;
1173 const unsigned int modmasks[] =
1174 {
1175 Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
1176 };
1177
1178 requestedmeta = realmeta = realalt = 0;
1179 rsmod = rs[Rs_modifier];
1180
1181 if (rsmod
1182 && strcasecmp (rsmod, "mod1") >= 0 && strcasecmp (rsmod, "mod5") <= 0)
1183 requestedmeta = rsmod[3] - '0';
1184
1185 map = XGetModifierMapping (dpy);
1186 kc = map->modifiermap;
1187
1188 for (i = 1; i < 6; i++)
1189 {
1190 k = (i + 2) * map->max_keypermod; /* skip shift/lock/control */
1191
1192 for (j = map->max_keypermod; j--; k++)
1193 {
1194 if (kc[k] == 0)
1195 break;
1196
1197 switch (rxvt_XKeycodeToKeysym (dpy, kc[k], 0))
1198 {
1199 case XK_Num_Lock:
1200 ModNumLockMask = modmasks[i - 1];
1201 continue;
1202
1203 case XK_ISO_Level3_Shift:
1204 ModLevel3Mask = modmasks[i - 1];
1205 continue;
1206
1207 case XK_Meta_L:
1208 case XK_Meta_R:
1209 cm = "meta";
1210 realmeta = i;
1211 break;
1212
1213 case XK_Alt_L:
1214 case XK_Alt_R:
1215 cm = "alt";
1216 realalt = i;
1217 break;
1218
1219 case XK_Super_L:
1220 case XK_Super_R:
1221 cm = "super";
1222 break;
1223
1224 case XK_Hyper_L:
1225 case XK_Hyper_R:
1226 cm = "hyper";
1227 break;
1228
1229 default:
1230 continue;
1231 }
1232
1233 if (rsmod && strncasecmp (rsmod, cm, strlen (cm)) == 0)
1234 requestedmeta = i;
1235 }
1236 }
1237
1238 XFreeModifiermap (map);
1239
1240 i = requestedmeta ? requestedmeta
1241 : realmeta ? realmeta
1242 : realalt ? realalt
1243 : 0;
1244
1245 if (i)
1246 ModMetaMask = modmasks[i - 1];
1247 }
1248
1249 void
1250 rxvt_term::set_icon (const char *file)
1251 {
1252 #if HAVE_PIXBUF && ENABLE_EWMH
1253 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (file, NULL);
1254 if (!pixbuf)
1255 {
1256 rxvt_warn ("Loading image icon failed, continuing without.\n");
1257 return;
1258 }
1259
1260 unsigned int w = gdk_pixbuf_get_width (pixbuf);
1261 unsigned int h = gdk_pixbuf_get_height (pixbuf);
1262
1263 if (!IN_RANGE_INC (w, 1, 16383) || !IN_RANGE_INC (h, 1, 16383))
1264 {
1265 rxvt_warn ("Icon image too big, continuing without.\n");
1266 g_object_unref (pixbuf);
1267 return;
1268 }
1269
1270 if (long *buffer = (long *)malloc ((2 + w * h) * sizeof (long)))
1271 {
1272 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
1273 unsigned char *row = gdk_pixbuf_get_pixels (pixbuf);
1274 int channels = gdk_pixbuf_get_n_channels (pixbuf);
1275
1276 buffer [0] = w;
1277 buffer [1] = h;
1278 for (int i = 0; i < h; i++)
1279 {
1280 for (int j = 0; j < w; j++)
1281 {
1282 unsigned char *pixel = row + j * channels;
1283 long value;
1284
1285 if (channels == 4)
1286 value = pixel[3];
1287 else
1288 value = (unsigned char)0x00ff;
1289
1290 value = (value << 8) + pixel[0];
1291 value = (value << 8) + pixel[1];
1292 value = (value << 8) + pixel[2];
1293 buffer[(i * w + j) + 2] = value;
1294 }
1295
1296 row += rowstride;
1297 }
1298
1299 XChangeProperty (dpy, parent, xa[XA_NET_WM_ICON], XA_CARDINAL, 32,
1300 PropModeReplace, (const unsigned char *) buffer, 2 + w * h);
1301 free (buffer);
1302 }
1303 else
1304 rxvt_warn ("Memory allocation for icon hint failed, continuing without.\n");
1305
1306 g_object_unref (pixbuf);
1307 #endif
1308 }
1309
1310 /*----------------------------------------------------------------------*/
1311 /* Open and map the window */
1312 void
1313 rxvt_term::create_windows (int argc, const char *const *argv)
1314 {
1315 XClassHint classHint;
1316 XWMHints wmHint;
1317 #if ENABLE_FRILLS
1318 MWMHints mwmhints = { };
1319 #endif
1320 XGCValues gcvalue;
1321 XSetWindowAttributes attributes;
1322 Window top, parent;
1323
1324 dLocal (Display *, dpy);
1325
1326 /* grab colors before netscape does */
1327 get_colors ();
1328
1329 if (!set_fonts ())
1330 rxvt_fatal ("unable to load base fontset, please specify a valid one using -fn, aborting.\n");
1331
1332 parent = display->root;
1333
1334 attributes.override_redirect = !!option (Opt_override_redirect);
1335
1336 #if ENABLE_FRILLS
1337 if (option (Opt_borderLess))
1338 {
1339 if (XInternAtom (dpy, "_MOTIF_WM_INFO", True) == None)
1340 {
1341 // rxvt_warn("Window Manager does not support MWM hints. Bypassing window manager control for borderless window.\n");
1342 attributes.override_redirect = true;
1343 }
1344 else
1345 {
1346 mwmhints.flags = MWM_HINTS_DECORATIONS;
1347 }
1348 }
1349 #endif
1350
1351 #if ENABLE_XEMBED
1352 if (rs[Rs_embed])
1353 {
1354 XWindowAttributes wattr;
1355
1356 parent = strtol (rs[Rs_embed], 0, 0);
1357
1358 if (!XGetWindowAttributes (dpy, parent, &wattr))
1359 rxvt_fatal ("invalid window-id specified with -embed, aborting.\n");
1360
1361 window_calc (wattr.width, wattr.height);
1362 }
1363 #endif
1364
1365 window_calc (0, 0);
1366
1367 /* sub-window placement & size in rxvt_term::resize_all_windows () */
1368 attributes.background_pixel = pix_colors_focused [Color_border];
1369 attributes.border_pixel = pix_colors_focused [Color_border];
1370 attributes.colormap = cmap;
1371
1372 top = XCreateWindow (dpy, parent,
1373 szHint.x, szHint.y,
1374 szHint.width, szHint.height,
1375 ext_bwidth,
1376 depth, InputOutput, visual,
1377 CWColormap | CWBackPixel | CWBorderPixel | CWOverrideRedirect,
1378 &attributes);
1379
1380 this->parent = top;
1381
1382 set_title (rs [Rs_title]);
1383 set_icon_name (rs [Rs_iconName]);
1384
1385 classHint.res_name = (char *)rs[Rs_name];
1386 classHint.res_class = (char *)RESCLASS;
1387
1388 wmHint.flags = InputHint | StateHint | WindowGroupHint;
1389 wmHint.input = True;
1390 wmHint.initial_state = option (Opt_iconic) ? IconicState
1391 : option (Opt_dockapp) ? WithdrawnState
1392 : NormalState;
1393 wmHint.window_group = top;
1394
1395 XmbSetWMProperties (dpy, top, NULL, NULL, (char **)argv, argc,
1396 &szHint, &wmHint, &classHint);
1397 #if ENABLE_EWMH
1398 /*
1399 * set up icon hint
1400 * rs [Rs_iconfile] is path to icon
1401 */
1402
1403 if (rs [Rs_iconfile])
1404 set_icon (rs [Rs_iconfile]);
1405 #endif
1406
1407 #if ENABLE_FRILLS
1408 if (mwmhints.flags)
1409 XChangeProperty (dpy, top, xa[XA_MOTIF_WM_HINTS], xa[XA_MOTIF_WM_HINTS], 32,
1410 PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS);
1411 #endif
1412
1413 Atom protocols[] = {
1414 xa[XA_WM_DELETE_WINDOW],
1415 #if ENABLE_EWMH
1416 xa[XA_NET_WM_PING],
1417 #endif
1418 };
1419
1420 XSetWMProtocols (dpy, top, protocols, ecb_array_length (protocols));
1421
1422 #if ENABLE_FRILLS
1423 if (rs[Rs_transient_for])
1424 XSetTransientForHint (dpy, top, (Window)strtol (rs[Rs_transient_for], 0, 0));
1425 #endif
1426
1427 #if ENABLE_EWMH
1428 long pid = getpid ();
1429
1430 XChangeProperty (dpy, top,
1431 xa[XA_NET_WM_PID], XA_CARDINAL, 32,
1432 PropModeReplace, (unsigned char *)&pid, 1);
1433
1434 // _NET_WM_WINDOW_TYPE is NORMAL, which is the default
1435 #endif
1436
1437 XSelectInput (dpy, top,
1438 KeyPressMask
1439 #if (MOUSE_WHEEL && MOUSE_SLIP_WHEELING) || ENABLE_FRILLS || ISO_14755
1440 | KeyReleaseMask
1441 #endif
1442 | FocusChangeMask | VisibilityChangeMask
1443 | ExposureMask | StructureNotifyMask);
1444
1445 termwin_ev.start (display, top);
1446
1447 /* vt cursor: Black-on-White is standard, but this is more popular */
1448 unsigned int shape = XC_xterm;
1449
1450 #ifdef HAVE_XMU
1451 if (rs[Rs_pointerShape])
1452 {
1453 int stmp = XmuCursorNameToIndex (rs[Rs_pointerShape]);
1454 if (stmp >= 0)
1455 shape = stmp;
1456 }
1457 #endif
1458
1459 TermWin_cursor = XCreateFontCursor (dpy, shape);
1460
1461 /* the vt window */
1462 vt = XCreateSimpleWindow (dpy, top,
1463 window_vt_x, window_vt_y,
1464 vt_width, vt_height,
1465 0,
1466 pix_colors_focused[Color_fg],
1467 pix_colors_focused[Color_bg]);
1468
1469 attributes.bit_gravity = NorthWestGravity;
1470 XChangeWindowAttributes (dpy, vt, CWBitGravity, &attributes);
1471
1472 vt_emask = ExposureMask | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask;
1473
1474 if (option (Opt_pointerBlank))
1475 vt_emask |= PointerMotionMask;
1476 else
1477 vt_emask |= Button1MotionMask | Button3MotionMask;
1478
1479 vt_select_input ();
1480
1481 vt_ev.start (display, vt);
1482
1483 /* graphics context for the vt window */
1484 gcvalue.foreground = pix_colors[Color_fg];
1485 gcvalue.background = pix_colors[Color_bg];
1486 gcvalue.graphics_exposures = 0;
1487
1488 gc = XCreateGC (dpy, vt,
1489 GCForeground | GCBackground | GCGraphicsExposures,
1490 &gcvalue);
1491
1492 drawable = new rxvt_drawable (this, vt);
1493
1494 #ifdef OFF_FOCUS_FADING
1495 // initially we are in unfocused state
1496 if (rs[Rs_fade])
1497 pix_colors = pix_colors_unfocused;
1498 #endif
1499
1500 pointer_unblank ();
1501 scr_recolor ();
1502 }
1503
1504 /*----------------------------------------------------------------------*/
1505 /*
1506 * Run the command in a subprocess and return a file descriptor for the
1507 * master end of the pseudo-teletype pair with the command talking to
1508 * the slave.
1509 */
1510 void
1511 rxvt_term::run_command (const char *const *argv)
1512 {
1513 #if ENABLE_FRILLS
1514 if (rs[Rs_pty_fd])
1515 {
1516 pty->pty = atoi (rs[Rs_pty_fd]);
1517
1518 if (pty->pty >= 0)
1519 {
1520 if (getfd_hook)
1521 pty->pty = (*getfd_hook) (pty->pty);
1522
1523 if (pty->pty < 0)
1524 rxvt_fatal ("unusable pty-fd filehandle, aborting.\n");
1525 }
1526 }
1527 else
1528 #endif
1529 if (!pty->get ())
1530 rxvt_fatal ("can't initialize pseudo-tty, aborting.\n");
1531
1532 fcntl (pty->pty, F_SETFL, O_NONBLOCK);
1533
1534 struct termios tio = def_tio;
1535
1536 #ifndef NO_BACKSPACE_KEY
1537 if (rs[Rs_backspace_key][0] && !rs[Rs_backspace_key][1])
1538 tio.c_cc[VERASE] = rs[Rs_backspace_key][0];
1539 else if (strcmp (rs[Rs_backspace_key], "DEC") == 0)
1540 tio.c_cc[VERASE] = '\177'; /* the initial state anyway */
1541 #endif
1542
1543 /* init terminal attributes */
1544 cfsetospeed (&tio, BAUDRATE);
1545 cfsetispeed (&tio, BAUDRATE);
1546 tcsetattr (pty->tty, TCSANOW, &tio);
1547 pty->set_utf8_mode (enc_utf8);
1548
1549 /* set initial window size */
1550 tt_winch ();
1551
1552 #if ENABLE_FRILLS
1553 if (rs[Rs_pty_fd])
1554 return;
1555 #endif
1556
1557 /* spin off the command interpreter */
1558 switch (cmd_pid = fork ())
1559 {
1560 case -1:
1561 {
1562 cmd_pid = 0;
1563 rxvt_fatal ("can't fork, aborting.\n");
1564 }
1565 case 0:
1566 init_env ();
1567
1568 if (!pty->make_controlling_tty ())
1569 fprintf (stderr, "%s: could not obtain control of tty.", RESNAME);
1570 else
1571 {
1572 /* Reopen stdin, stdout and stderr over the tty file descriptor */
1573 dup2 (pty->tty, STDIN_FILENO);
1574 dup2 (pty->tty, STDOUT_FILENO);
1575 dup2 (pty->tty, STDERR_FILENO);
1576
1577 // close all our file handles that we do no longer need
1578 for (rxvt_term **t = termlist.begin (); t < termlist.end (); t++)
1579 {
1580 if ((*t)->pty->pty > 2) close ((*t)->pty->pty);
1581 if ((*t)->pty->tty > 2) close ((*t)->pty->tty);
1582 }
1583
1584 run_child (argv);
1585 fprintf (stderr, "%s: unable to exec child.", RESNAME);
1586 }
1587
1588 _exit (EXIT_FAILURE);
1589
1590 default:
1591 if (!option (Opt_utmpInhibit))
1592 {
1593 #ifdef LOG_ONLY_ON_LOGIN
1594 bool login_shell = option (Opt_loginShell);
1595 #else
1596 bool login_shell = true;
1597 #endif
1598 pty->login (cmd_pid, login_shell, rs[Rs_display_name]);
1599 }
1600
1601 pty->close_tty ();
1602
1603 child_ev.start (cmd_pid);
1604
1605 HOOK_INVOKE ((this, HOOK_CHILD_START, DT_INT, cmd_pid, DT_END));
1606 break;
1607 }
1608 }
1609
1610 /* ------------------------------------------------------------------------- *
1611 * CHILD PROCESS OPERATIONS *
1612 * ------------------------------------------------------------------------- */
1613 /*
1614 * The only open file descriptor is the slave tty - so no error messages.
1615 * returns are fatal
1616 */
1617 int
1618 rxvt_term::run_child (const char *const *argv)
1619 {
1620 char *login;
1621
1622 if (option (Opt_console))
1623 {
1624 /* be virtual console, fail silently */
1625 #ifdef TIOCCONS
1626 unsigned int on = 1;
1627
1628 ioctl (STDIN_FILENO, TIOCCONS, &on);
1629 #elif defined (SRIOCSREDIR)
1630 int fd;
1631
1632 fd = open (CONSOLE, O_WRONLY, 0);
1633 if (fd >= 0)
1634 {
1635 ioctl (fd, SRIOCSREDIR, STDIN_FILENO);
1636 close (fd);
1637 }
1638 #endif /* SRIOCSREDIR */
1639 }
1640
1641 /* reset signals and spin off the command interpreter */
1642 signal (SIGINT, SIG_DFL);
1643 signal (SIGQUIT, SIG_DFL);
1644 signal (SIGCHLD, SIG_DFL);
1645 signal (SIGHUP, SIG_DFL);
1646 signal (SIGPIPE, SIG_DFL);
1647 /*
1648 * mimic login's behavior by disabling the job control signals
1649 * a shell that wants them can turn them back on
1650 */
1651 #ifdef SIGTSTP
1652 signal (SIGTSTP, SIG_IGN);
1653 signal (SIGTTIN, SIG_IGN);
1654 signal (SIGTTOU, SIG_IGN);
1655 #endif /* SIGTSTP */
1656
1657 /* command interpreter path */
1658 if (argv)
1659 {
1660 # ifdef DEBUG_CMD
1661 int i;
1662
1663 for (i = 0; argv[i]; i++)
1664 fprintf (stderr, "argv [%d] = \"%s\"\n", i, argv[i]);
1665 # endif
1666
1667 execvp (argv[0], (char *const *)argv);
1668 /* no error message: STDERR is closed! */
1669 }
1670 else
1671 {
1672 const char *argv0, *shell;
1673
1674 if ((shell = getenv ("SHELL")) == NULL || *shell == '\0')
1675 shell = "/bin/sh";
1676
1677 argv0 = rxvt_basename (shell);
1678
1679 if (option (Opt_loginShell))
1680 {
1681 login = (char *)rxvt_malloc (strlen (argv0) + 2);
1682
1683 login[0] = '-';
1684 strcpy (&login[1], argv0);
1685 argv0 = login;
1686 }
1687
1688 execlp (shell, argv0, (char *)0);
1689 /* no error message: STDERR is closed! */
1690 }
1691
1692 return -1;
1693 }
1694
1695 /*----------------------- end-of-file (C source) -----------------------*/