1 /*
2    netrik -- The ANTRIK Internet Viewer
3    Copyright (C) Olaf D. Buddenhagen AKA antrik, et al (see AUTHORS)
4    Published under the GNU GPL; see LICENSE for details.
5 */
6 /*
7  * screen.c -- all screen handling functions (curses wrappers).
8  *
9  * (C) 2001, 2002, 2003 antrik
10  *
11  * Presently the full screen functions aren't used by the main program...
12  */
13 #include <curses.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <term.h>
18 
19 #include "cfg.h"
20 #include "screen.h"
21 #include "winch.h"
22 
23 /* init curses full screen mode;
24  * includes initializing color mode and color pairs */
start_curses(void)25 void start_curses(void)
26 {
27    initscr();    /* init curses */
28 
29    /* set options */
30    if((cfg.color && start_color()==ERR)
31       || cbreak()==ERR    /* unbuffered input */
32       || noecho()==ERR    /* no key echo */
33       || intrflush(stdscr, FALSE)==ERR    /* don't flush output on signals */
34       || keypad(stdscr, TRUE)==ERR    /* translate function key sequences */
35    ) {
36       endwin();
37       fprintf(stderr, "error initializing curses in fullscreen mode\n");
38       exit(1);
39    }
40    nonl();    /* don't mess with cr on keyboard input */
41    idlok(stdscr, TRUE);    /* allow hardware scrolling */
42 
43    /* prepare color pairs */
44    if(cfg.color) {
45       int	pair;    /* currently processed color pair */
46 
47       for(pair=1; pair<64; ++pair) {    /* 8x8 color pairs (all combinations of fg and bg color); pair 0 is hard-wired (to white on black instead of black on black) */
48 	 int	fg, bg;
49 
50 	 fg=(pair+7)%8; bg=pair/8;    /* fg colorspace rotated, so white on black will be mapped to pair 0 */
51 	 if(!cfg.force_colors) {
52 	    if(use_default_colors()!=ERR) {    /* can use default colors */
53 	       if(bg==COLOR_BLACK)
54 		  bg=-1;    /* use terminal default */
55 	       if(fg==COLOR_WHITE)
56 		  fg=-1;
57 	    }
58 	 }
59 	 if(init_pair(pair, fg, bg)==ERR) {    /* set foreground and background of pair */
60 	    endwin();
61 	    fprintf(stderr, "error initializing curses in fullscreen mode (can't set color pair %d)\n", pair);
62 	    exit(1);
63 	 }
64       }
65 
66       if(cfg.force_colors)
67 	 bkgdset(COLOR_PAIR(0));
68    }
69 }
70 
71 /* set screen attributes (color, bold)
72  * (standard colors for white foreground/black background are handled in init) */
set_color(color)73 void set_color(color)
74 int	color;
75 {
76    int	attrs=A_NORMAL;
77 
78    int	fg=(color+1)&0x07;    /* foreground color */
79    int	bg=(color&0x70)>>4;    /* background */
80 
81    if(!cfg.color)
82       return;
83 
84    /* prepare attributes */
85    if(color&0x80) {    /* bright background */
86       if(cfg.inverse_bold) {    /* can obtain bright background only with reverse video */
87 	 attrs|=A_BOLD|A_REVERSE;    /* set bright background (reversed bright foreground) */
88 	 fg^=bg; bg^=fg; fg^=bg;    /* swap */
89 	 bg=(bg-1)&7; fg=(fg+1)&7;    /* undo color rotation for new background (old forground) and apply to new forground instead */
90       } else    /* can set bright background directly */
91 	 attrs|=A_BLINK;
92    }
93    if(color&0x08)    /* bright foreground */
94       attrs|=A_BOLD;
95 
96    attrs|=COLOR_PAIR(bg<<3|fg);
97 
98    attrset(attrs);
99 }
100 
101 /* leave curses full screen mode (possibly temporarily) */
end_fullscreen(void)102 void end_fullscreen(void)
103 {
104    /* free bottom line (scroll one line) */
105    move(0,0);
106    deleteln();
107    refresh();
108 
109    endwin();
110 
111    enable_winch();    /* allow SIGWINCH outside fullscreen mode, so it can be handled by readline() (curses will adapt when restarting fullscreen) */
112 }
113 
114 
115 /* terminal control sequences */
116 static char	*setaf;    /* foreground color */
117 static char	*setab;    /* background color */
118 
119 /* init curses (not full screen) and read some control sequence strings
120  * return screen width */
init_curses(void)121 int init_curses(void)
122 {
123    int	width;
124 
125    if(setupterm(NULL, 1, NULL)==ERR) {    /* init */
126       fprintf(stderr, "Error initializing curses in raw mode.\n");
127       exit(1);
128    }
129 
130    width=tigetnum("cols");
131    if(width<=0) {
132       fprintf(stderr, "Error initializing curses in raw mode. (Can't get screen size.)\n");
133       exit(1);
134    }
135 
136    if(cfg.color) {
137       setaf=tigetstr("setaf");    /* set foreground color */
138       setab=tigetstr("setab");    /* background color */
139       if(setaf==NULL || setab==NULL) {
140 	 cfg.color=0;
141 	 fprintf(stderr, "Can't get color capabilities -- starting in monochrome mode.\n\nIf this is what you want, use --monochrome option to suppress this warning. Otherwise, please check your $TERM environment variable. (See README for details.)\n\nPress <return> to continue.\n");
142 	 getchar();
143       }
144 
145       /* determine whether terminal needs workaround to display bright background colors */
146       if(cfg.inverse_bold < 0) {    /* not forced by command line option -> guess */
147 	 char	*term;
148 
149 	 term=getenv("TERM");
150 	 if(term==NULL)
151 	    term="";
152 
153 	 cfg.inverse_bold=(strstr(term, "xterm")!=NULL);    /* xterm needs it */
154       }
155    }
156 
157    return width;
158 }
159 
160 /* set screen attributes (color, bold) in raw mode
161  * color white is not set; standard attributes are kept instead;
162  * likewise for black background */
set_color_raw(color)163 void set_color_raw(color)
164 int	color;
165 {
166    chtype	attrs=A_NORMAL;
167 
168    int	fg=color&0x07;    /* foreground color */
169    int	bg=(color&0x70)>>4;    /* background */
170 
171    if(!cfg.color)
172       return;
173 
174    /* prepare attributes */
175    if(color&0x80) {    /* bright background */
176       if(cfg.inverse_bold) {    /* can obtain bright background only with reverse video */
177 	 attrs|=A_BOLD|A_REVERSE;    /* set bright background (reversed bright foreground) */
178 	 fg^=bg; bg^=fg; fg^=bg;    /* swap */
179       } else    /* can set bright background directly */
180 	 attrs|=A_BLINK;
181    }
182    if(color&0x08)    /* bright foreground */
183       attrs|=A_BOLD;
184 
185    /* set */
186    vidattr(attrs);
187    if(bg!=COLOR_BLACK)    /* not black (or force_colors) -> set background */
188       putp(tparm(setab, bg));
189    if(fg!=COLOR_WHITE)    /* not white (or force_colors) -> set color */
190       putp(tparm(setaf, fg));
191 }
192 
193 /* reset screen attributes to default */
reset_color_raw(void)194 void reset_color_raw(void)
195 {
196    if(!cfg.color)
197       return;
198 
199    vidattr(A_BOLD); vidattr(A_NORMAL);    /* force reset (curses doesn't know about color changes in raw mode...) */
200 }
201