xref: /freebsd/sys/dev/syscons/daemon/daemon_saver.c (revision 2aebedc3ad9e722b272254e6dd3a12e399595e57)
1 /*-
2  * Copyright (c) 1997 Sandro Sigala, Brescia, Italy.
3  * Copyright (c) 1997 Chris Shenton
4  * Copyright (c) 1995 S ren Schmidt
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer
12  *    in this position and unchanged.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *	$Id: daemon_saver.c,v 1.11 1998/09/17 19:40:30 sos Exp $
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/module.h>
34 #include <sys/malloc.h>
35 #include <sys/kernel.h>
36 #include <sys/sysctl.h>
37 
38 #include <machine/md_var.h>
39 #include <machine/pc/display.h>
40 
41 #include <saver.h>
42 
43 #define CONSOLE_VECT(x, y) \
44 	(window + (y)*cur_console->xsize + (x))
45 
46 #define DAEMON_MAX_WIDTH	32
47 #define DAEMON_MAX_HEIGHT	19
48 
49 static char *message;
50 static int messagelen;
51 static u_short *window;
52 
53 /* Who is the author of this ASCII pic? */
54 
55 static char *daemon_pic[] = {
56         "             ,        ,",
57 	"            /(        )`",
58 	"            \\ \\___   / |",
59 	"            /- _  `-/  '",
60 	"           (/\\/ \\ \\   /\\",
61 	"           / /   | `    \\",
62 	"           O O   ) /    |",
63 	"           `-^--'`<     '",
64 	"          (_.)  _  )   /",
65 	"           `.___/`    /",
66 	"             `-----' /",
67 	"<----.     __ / __   \\",
68 	"<----|====O)))==) \\) /====",
69 	"<----'    `--' `.__,' \\",
70 	"             |        |",
71 	"              \\       /       /\\",
72 	"         ______( (_  / \\______/",
73 	"       ,'  ,-----'   |",
74 	"       `--{__________)",
75 	NULL
76 };
77 
78 static char *daemon_attr[] = {
79         "             R        R",
80 	"            RR        RR",
81 	"            R RRRR   R R",
82 	"            RR W  RRR  R",
83 	"           RWWW W R   RR",
84 	"           W W   W R    R",
85 	"           B B   W R    R",
86 	"           WWWWWWRR     R",
87 	"          RRRR  R  R   R",
88 	"           RRRRRRR    R",
89 	"             RRRRRRR R",
90 	"YYYYYY     RR R RR   R",
91 	"YYYYYYYYYYRRRRYYR RR RYYYY",
92 	"YYYYYY    RRRR RRRRRR R",
93 	"             R        R",
94 	"              R       R       RR",
95 	"         CCCCCCR RR  R RRRRRRRR",
96 	"       CC  CCCCCCC   C",
97 	"       CCCCCCCCCCCCCCC",
98 	NULL
99 };
100 
101 /*
102  * Reverse a graphics character, or return unaltered if no mirror;
103  * should do alphanumerics too, but I'm too lazy. <cshenton@it.hq.nasa.gov>
104  */
105 
106 static char
107 xflip_symbol(char symbol)
108 {
109 	static const char lchars[] = "`'(){}[]\\/<>";
110 	static const char rchars[] = "'`)(}{][/\\><";
111 	int pos;
112 
113 	for (pos = 0; lchars[pos] != '\0'; pos++)
114 		if (lchars[pos] == symbol)
115 			return rchars[pos];
116 
117 	return symbol;
118 }
119 
120 static void
121 clear_daemon(int xpos, int ypos, int dxdir, int xoff, int yoff,
122 	    int xlen, int ylen)
123 {
124 	int y;
125 
126 	if (xlen <= 0)
127 		return;
128 	for (y = yoff; y < ylen; y++)
129 		fillw(((FG_LIGHTGREY|BG_BLACK) << 8) | scr_map[0x20],
130 		      CONSOLE_VECT(xpos + xoff, ypos + y), xlen - xoff);
131 }
132 
133 static void
134 draw_daemon(int xpos, int ypos, int dxdir, int xoff, int yoff,
135 	    int xlen, int ylen)
136 {
137 	int x, y;
138 	int px;
139 	int attr;
140 
141 	for (y = yoff; y < ylen; y++) {
142 		if (dxdir < 0)
143 			px = xoff;
144 		else
145 			px = DAEMON_MAX_WIDTH - xlen;
146 		if (px >= strlen(daemon_pic[y]))
147 			continue;
148 		for (x = xoff; (x < xlen) && (daemon_pic[y][px] != '\0'); x++, px++) {
149 			switch (daemon_attr[y][px]) {
150 			case 'R': attr = (FG_LIGHTRED|BG_BLACK)<<8; break;
151 			case 'Y': attr = (FG_YELLOW|BG_BLACK)<<8; break;
152 			case 'B': attr = (FG_LIGHTBLUE|BG_BLACK)<<8; break;
153 			case 'W': attr = (FG_LIGHTGREY|BG_BLACK)<<8; break;
154 			case 'C': attr = (FG_CYAN|BG_BLACK)<<8; break;
155 			default: attr = (FG_WHITE|BG_BLACK)<<8; break;
156 			}
157 			if (dxdir < 0) {	/* Moving left */
158 				*CONSOLE_VECT(xpos + x, ypos + y) =
159 					scr_map[daemon_pic[y][px]]|attr;
160 			} else {		/* Moving right */
161 				*CONSOLE_VECT(xpos + DAEMON_MAX_WIDTH - px - 1, ypos + y) =
162 					scr_map[xflip_symbol(daemon_pic[y][px])]|attr;
163 			}
164 		}
165 	}
166 }
167 
168 static void
169 clear_string(int xpos, int ypos, int xoff, char *s, int len)
170 {
171 	if (len <= 0)
172 		return;
173 	fillw(((FG_LIGHTGREY|BG_BLACK) << 8) | scr_map[0x20],
174 	      CONSOLE_VECT(xpos + xoff, ypos), len - xoff);
175 }
176 
177 static void
178 draw_string(int xpos, int ypos, int xoff, char *s, int len)
179 {
180 	int x;
181 
182 	for (x = xoff; x < len; x++)
183 		*CONSOLE_VECT(xpos + x, ypos) =
184 			scr_map[s[x]]|(FG_LIGHTGREEN|BG_BLACK)<<8;
185 }
186 
187 static void
188 daemon_saver(int blank)
189 {
190 	static int txpos = 10, typos = 10;
191 	static int txdir = -1, tydir = -1;
192 	static int dxpos = 0, dypos = 0;
193 	static int dxdir = 1, dydir = 1;
194 	static int moved_daemon = 0;
195 	static int xoff, yoff, toff;
196 	static int xlen, ylen, tlen;
197 	scr_stat *scp = cur_console;
198 	int min, max;
199 
200 	if (blank) {
201 		if (!ISTEXTSC(scp))
202 			return;
203 		if (scrn_blanked == 0) {
204 			scp->status |= SAVER_RUNNING;
205 			window = (u_short *)(*biosvidsw.adapter)(scp->adp)->va_window;
206 			/* clear the screen and set the border color */
207 			fillw(((FG_LIGHTGREY|BG_BLACK) << 8) | scr_map[0x20],
208 			      window, scp->xsize * scp->ysize);
209 			set_border(scp, 0);
210 			xlen = ylen = tlen = 0;
211 		}
212 		if (scrn_blanked++ < 2)
213 			return;
214 		scrn_blanked = 1;
215 
216  		clear_daemon(dxpos, dypos, dxdir, xoff, yoff, xlen, ylen);
217 		clear_string(txpos, typos, toff, (char *)message, tlen);
218 
219 		if (++moved_daemon) {
220 			/*
221 			 * The daemon picture may be off the screen, if
222 			 * screen size is chagened while the screen
223 			 * saver is inactive. Make sure the origin of
224 			 * the picture is between min and max.
225 			 */
226 			if (scp->xsize <= DAEMON_MAX_WIDTH) {
227 				/*
228 				 * If the screen width is too narrow, we
229 				 * allow part of the picture go off
230 				 * the screen so that the daemon won't
231 				 * flip too often.
232 				 */
233 				min = scp->xsize - DAEMON_MAX_WIDTH - 10;
234 				max = 10;
235 			} else {
236 				min = 0;
237 				max = scp->xsize - DAEMON_MAX_WIDTH;
238 			}
239 			if (dxpos <= min) {
240 				dxpos = min;
241 				dxdir = 1;
242 			} else if (dxpos >= max) {
243 				dxpos = max;
244 				dxdir = -1;
245 			}
246 
247 			if (scp->ysize <= DAEMON_MAX_HEIGHT) {
248 				min = scp->ysize - DAEMON_MAX_HEIGHT - 10;
249 				max = 10;
250 			} else {
251 				min = 0;
252 				max = scp->ysize - DAEMON_MAX_HEIGHT;
253 			}
254 			if (dypos <= min) {
255 				dypos = min;
256 				dydir = 1;
257 			} else if (dypos >= max) {
258 				dypos = max;
259 				dydir = -1;
260 			}
261 
262 			moved_daemon = -1;
263 			dxpos += dxdir; dypos += dydir;
264 
265 			/* clip the picture */
266 			xoff = 0;
267 			xlen = DAEMON_MAX_WIDTH;
268 			if (dxpos + xlen <= 0)
269 				xlen = 0;
270 			else if (dxpos < 0)
271 				xoff = -dxpos;
272 			if (dxpos >= scp->xsize)
273 				xlen = 0;
274 			else if (dxpos + xlen > scp->xsize)
275 				xlen = scp->xsize - dxpos;
276 			yoff = 0;
277 			ylen = DAEMON_MAX_HEIGHT;
278 			if (dypos + ylen <= 0)
279 				ylen = 0;
280 			else if (dypos < 0)
281 				yoff = -dypos;
282 			if (dypos >= scp->ysize)
283 				ylen = 0;
284 			else if (dypos + ylen > scp->ysize)
285 				ylen = scp->ysize - dypos;
286 		}
287 
288 		if (scp->xsize <= messagelen) {
289 			min = scp->xsize - messagelen - 10;
290 			max = 10;
291 		} else {
292 			min = 0;
293 			max = scp->xsize - messagelen;
294 		}
295 		if (txpos <= min) {
296 			txpos = min;
297 			txdir = 1;
298 		} else if (txpos >= max) {
299 			txpos = max;
300 			txdir = -1;
301 		}
302 		if (typos <= 0) {
303 			typos = 0;
304 			tydir = 1;
305 		} else if (typos >= scp->ysize - 1) {
306 			typos = scp->ysize - 1;
307 			tydir = -1;
308 		}
309 		txpos += txdir; typos += tydir;
310 
311 		toff = 0;
312 		tlen = messagelen;
313 		if (txpos + tlen <= 0)
314 			tlen = 0;
315 		else if (txpos < 0)
316 			toff = -txpos;
317 		if (txpos >= scp->xsize)
318 			tlen = 0;
319 		else if (txpos + tlen > scp->xsize)
320 			tlen = scp->xsize - txpos;
321 
322  		draw_daemon(dxpos, dypos, dxdir, xoff, yoff, xlen, ylen);
323 		draw_string(txpos, typos, toff, (char *)message, tlen);
324 	} else {
325 		if (scrn_blanked > 0) {
326 			set_border(scp, scp->border);
327 			scrn_blanked = 0;
328 			scp->status &= ~SAVER_RUNNING;
329 		}
330 	}
331 }
332 
333 static int
334 daemon_saver_load(void)
335 {
336 	int err;
337 
338 	messagelen = strlen(hostname) + 3 + strlen(ostype) + 1 +
339 	    strlen(osrelease);
340 	message = malloc(messagelen + 1, M_DEVBUF, M_WAITOK);
341 	sprintf(message, "%s - %s %s", hostname, ostype, osrelease);
342 
343 	err = add_scrn_saver(daemon_saver);
344 	if (err != 0)
345 		free(message, M_DEVBUF);
346 	return err;
347 }
348 
349 static int
350 daemon_saver_unload(void)
351 {
352 	int err;
353 
354 	err = remove_scrn_saver(daemon_saver);
355 	if (err == 0)
356 		free(message, M_DEVBUF);
357 	return err;
358 }
359 
360 SAVER_MODULE(daemon_saver);
361