xref: /openbsd-src/usr.bin/top/screen.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* $OpenBSD: screen.c,v 1.19 2008/09/24 18:53:55 chl Exp $	 */
2 
3 /*
4  *  Top users/processes display for Unix
5  *  Version 3
6  *
7  * Copyright (c) 1984, 1989, William LeFebvre, Rice University
8  * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /*
32  * This file contains the routines that interface to termcap and stty/gtty.
33  *
34  * Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
35  *
36  * I put in code to turn on the TOSTOP bit while top was running, but I didn't
37  * really like the results.  If you desire it, turn on the preprocessor
38  * variable "TOStop".   --wnl
39  */
40 
41 #include <sys/types.h>
42 #include <sys/ioctl.h>
43 #include <curses.h>
44 #include <err.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <term.h>
48 #include <unistd.h>
49 
50 #include "top.h"
51 #include "screen.h"
52 #include "boolean.h"
53 
54 int	screen_length, screen_width;
55 char	ch_erase, ch_kill, smart_terminal;
56 
57 static struct termios old_settings, new_settings;
58 static char is_a_terminal = No;
59 
60 void
61 init_termcap(int interactive)
62 {
63 	char *term_name;
64 	int status;
65 
66 	/* set defaults in case we aren't smart */
67 	screen_width = MAX_COLS;
68 	screen_length = 0;
69 
70 	if (!interactive) {
71 		/* pretend we have a dumb terminal */
72 		smart_terminal = No;
73 		return;
74 	}
75 	/* assume we have a smart terminal until proven otherwise */
76 	smart_terminal = Yes;
77 
78 	/* get the terminal name */
79 	term_name = getenv("TERM");
80 
81 	/* if there is no TERM, assume it's a dumb terminal */
82 	/* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
83 	if (term_name == NULL) {
84 		smart_terminal = No;
85 		return;
86 	}
87 
88 	/* now get the termcap entry */
89 	if ((status = tgetent(NULL, term_name)) != 1) {
90 		if (status == -1)
91 			warnx("can't open termcap file");
92 		else
93 			warnx("no termcap entry for a `%s' terminal", term_name);
94 
95 		/* pretend it's dumb and proceed */
96 		smart_terminal = No;
97 		return;
98 	}
99 
100 	/* "hardcopy" immediately indicates a very stupid terminal */
101 	if (tgetflag("hc")) {
102 		smart_terminal = No;
103 		return;
104 	}
105 
106 	/* set up common terminal capabilities */
107 	if ((screen_length = tgetnum("li")) <= Header_lines) {
108 		screen_length = smart_terminal = 0;
109 		return;
110 	}
111 
112 	/* screen_width is a little different */
113 	if ((screen_width = tgetnum("co")) == -1)
114 		screen_width = 79;
115 	else
116 		screen_width -= 1;
117 
118         /* get necessary capabilities */
119         if (tgetstr("cl", NULL) == NULL || tgetstr("cm", NULL) == NULL) {
120                 smart_terminal = No;
121                 return;
122         }
123 
124 	/* get the actual screen size with an ioctl, if needed */
125 	/*
126 	 * This may change screen_width and screen_length, and it always sets
127 	 * lower_left.
128 	 */
129 	get_screensize();
130 
131 	/* if stdout is not a terminal, pretend we are a dumb terminal */
132 	if (tcgetattr(STDOUT_FILENO, &old_settings) == -1)
133 		smart_terminal = No;
134 }
135 
136 void
137 init_screen(void)
138 {
139 	/* get the old settings for safe keeping */
140 	if (tcgetattr(STDOUT_FILENO, &old_settings) != -1) {
141 		/* copy the settings so we can modify them */
142 		new_settings = old_settings;
143 		/* turn off ICANON, character echo and tab expansion */
144 		new_settings.c_lflag &= ~(ICANON | ECHO);
145 		new_settings.c_oflag &= ~(OXTABS);
146 		new_settings.c_cc[VMIN] = 1;
147 		new_settings.c_cc[VTIME] = 0;
148 
149 		(void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings);
150 		/* remember the erase and kill characters */
151 		ch_erase = old_settings.c_cc[VERASE];
152 		ch_kill = old_settings.c_cc[VKILL];
153 
154 		is_a_terminal = Yes;
155 #if 0
156 		/* send the termcap initialization string */
157 		putcap(terminal_init);
158 #endif
159 	}
160 	if (!is_a_terminal) {
161 		/* not a terminal at all---consider it dumb */
162 		smart_terminal = No;
163 	}
164 
165 	if (smart_terminal)
166 		initscr();
167 }
168 
169 void
170 end_screen(void)
171 {
172 	if (smart_terminal) {
173 		move(screen_length-1, 0);
174 		clrtoeol();
175 		refresh();
176 		endwin();
177 	}
178 	if (is_a_terminal)
179 		(void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &old_settings);
180 }
181 
182 void
183 reinit_screen(void)
184 {
185 #if 0
186 	/* install our settings if it is a terminal */
187 	if (is_a_terminal)
188 		(void) tcsetattr(STDOUT_FILENO, TCSADRAIN, &new_settings);
189 
190 	/* send init string */
191 	if (smart_terminal)
192 		putcap(terminal_init);
193 #endif
194 }
195 
196 void
197 get_screensize(void)
198 {
199 	struct winsize ws;
200 
201 	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
202 		if (ws.ws_row != 0)
203 			screen_length = ws.ws_row;
204 		if (ws.ws_col != 0)
205 			screen_width = ws.ws_col - 1;
206 	}
207 }
208 
209 void
210 go_home(void)
211 {
212 	if (smart_terminal) {
213 		move(0, 0);
214 		refresh();
215 	}
216 }
217