chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mupdisp / linvga.c
CommitLineData
69695f33
MW
1
2/* Copyright (c) 1997, 1998, 1999, 2000, 2002 by Arkkra Enterprises */
3/* All rights reserved */
4
5/* Functions to support displaying multipage bitmap
6 * (as from Ghostscript -sDEVICE=bit) using Linux svgalib.
7 * This was derived from the AT386 version, so maybe some things
8 * would have been done a bit differently if it were written from
9 * scratch for Linux, but this seems to work fine and to be
10 * plenty fast enough (at least on a Pentium or better ;-)
11 *
12 * Note that using mupdisp in non-X-window mode on Linux requires that it
13 * can write to the console device. To allow this, make mupdisp setuid to root:
14 * chown root mupdisp
15 * chmod 4755 mupdisp
16 */
17
18#if defined(linux) && ! defined(NO_VGA_LIB)
19
20
21#include "mupdisp.h"
22
23#include <stdio.h>
24#include <vga.h>
25#include <termio.h>
26#include <sys/kd.h>
27#include <sys/ioctl.h>
28
29#define BPL (80) /* bytes per line on screen */
30
31int Orig_video_mode;
32struct termio Orig_ttyinfo; /* to put keyboard back from raw mode */
33unsigned char Savefont[8192]; /* to put font back when we are done */
34int Console;
35
36static char *explanation =
37"\n\
38Note: The libvga used by this program\n\
39requires write permissions to /dev/console.\n\
40\n\
41The best way to enable that is to do the following (as root):\n\
42\tchown root mupdisp\n\
43\tchmod 4755 mupdisp\n\
44This makes mupdisp \"set user id\" to root.\n\
45\n\
46An alternate method would be to make /dev/console writeable by all:\n\
47\tchmod 666 /dev/console\n\
48but that method would pose a security risk, so it is not recommended.\n\n";
49static void setup_keyboard P((void));
50static void fix_keyboard P((void));
51\f
52
53/* set up for svgalib. Put video and keyboard in proper mode */
54
55void
56vgalib_setup()
57
58{
59 register int n; /* for setting signal catching */
60
61
62 /* will need to put keyboard into raw mode, save current state */
63 if (ioctl(0, TCGETA, &Orig_ttyinfo) < 0) {
64 (void) fprintf(stderr, "failed to get tty info\n");
65 generalcleanup(1);
66 }
67
68 /* some version of vgalib apparently do an atexit() call that causes
69 * the stty to be put in noecho mode. So arrange to undo that. */
70 atexit(fix_keyboard);
71
72 /* For some reason, vga_puttextmode doesn't seem to work on my
73 * system, but using the *IO_FONT ioctls does, so go with that.
74 * Save the current console font. */
75 if ((Console = open("/dev/console", 0)) < 0) {
76 (void) fprintf(stderr, "can't open /dev/console\n");
77 (void) fprintf(stderr, explanation);
78 generalcleanup(1);
79 }
80 if (ioctl(Console, GIO_FONT, Savefont) < 0) {
81 (void) fprintf(stderr, "unable to save console font\n");
82 generalcleanup(1);
83 }
84
85 vga_init();
86
87 /* get current video mode, so we can put it back when we're done */
88 Orig_video_mode = vga_getcurrentmode();
89
90 /* make sure we always clean up, so user isn't left stuck in raw and/or
91 * graphics mode. */
92 for (n = 1; n < NSIG; n++) {
93 if ( n != SIGKILL && n != SIGCLD) {
94 (void) signal(n, Conf_info_p->cleanup);
95 }
96 }
97 (void) signal(SIGWINCH, SIG_IGN);
98
99 /* put keyboard into raw mode */
100 setup_keyboard();
101
102 /* put screen into graphics mode */
103 vga_setmode(G640x480x16);
104}
105\f
106
107/* draw stuff onto screen. Draw starting at specified line of page */
108
109void
110vgalib_draw(line, small)
111
112int line; /* draw starting from this raster line of page */
113int small; /* YES if should draw small view of full page */
114
115{
116 register int i;
117 register int j;
118 unsigned char buff[MAX_BYTES_PER_LINE]; /* a row of bits to display */
119 int extra; /* how many unused bits in rightmost byte */
120 int mask; /* to clear out unused bits */
121 long offset; /* into bitmap file */
122 int fd; /* file to read bitmap from */
123 unsigned char vbuff[BPL * 8]; /* for one video scan line */
124 int jx8; /* j times 8 (to convert bits to bytes) */
125 int vbytes;
126
127
128 /* make sure we have a valid page to draw */
129 if (Currpage_p == (struct Pginfo *) 0) {
130 ( *(Conf_info_p->error) ) ("page # out of range");
131 return;
132 }
133
134 /* figure out where in the bitmap file this page is */
135 offset = Currpage_p->seqnum * BYTES_PER_PAGE;
136 fd = gen1file(small);
137 (void) lseek(fd, offset + line * BYTES_PER_LINE, SEEK_SET);
138
139 /* vgalib wants 1 byte per pixel, we have 1 bit per pixel,
140 * so multiply by 8 */
141 vbytes = BYTES_PER_LINE << 3;
142
143 /* read from file and put into form for vga library to use */
144 for (i = 0; i < Conf_info_p->vlines; i++) {
145 read(fd, buff, BYTES_PER_LINE);
146
147 /* if the page width is not on a byte boundary, blank
148 * out the partial byte at the edge */
149 for (mask = 1, extra = BYTES_PER_LINE & 0x7;
150 extra > 0; mask <<= 1, extra--) {
151 buff[BYTES_PER_LINE - 1] |= mask;
152 }
153
154 /* set line to all white except for area beyond right edge,
155 * which is set to all black */
156 memset(vbuff, 0xf, vbytes);
157 memset(vbuff + vbytes, 0, (BPL - BYTES_PER_LINE) << 3);
158
159 /* transfer bitmap row to vbuff, 1 bit of bitmap to 1 byte
160 * of vbuff. */
161 for (j = 0; j < BYTES_PER_LINE; j++) {
162 /* get j times 8 bits per byte */
163 jx8 = j << 3;
164
165 /* for each black bit, set appropriate
166 * vbuff byte to 0 */
167 for (mask = 0; mask < 8; mask++) {
168 if (buff[j] & (0x80 >> mask)) {
169 vbuff[jx8 + mask] = 0;
170 }
171 }
172 }
173
174 /* display this line */
175 vga_drawscanline(i, vbuff);
176 }
177}
178\f
179
180/* cleanup function.
181 * Put screen back into previous mode.
182 */
183
184void
185vgalib_cleanup(status)
186
187int status;
188
189{
190 /* put video back to normal */
191 vga_setmode(Orig_video_mode);
192 (void) ioctl(Console, PIO_FONT, Savefont);
193 close(Console);
194
195 /* put keyboard back to normal */
196 (void) ioctl(0, TCSETA, &Orig_ttyinfo);
197
198 /* call the non-terminal-type specific cleanup */
199 generalcleanup(status);
200}
201
202/* some versions of vgalib seem to put things into noecho mode. So undo that. */
203
204static void
205fix_keyboard()
206{
207 (void) ioctl(0, TCSETA, &Orig_ttyinfo);
208}
209\f
210
211/* read from keyboard and call do_cmd for each key read.
212 * Commands are described in
213 * the comment at the beginning of do_cmd() */
214
215void
216vgalib_user_interf()
217
218{
219 int c; /* char read from keyboard */
220 int special = 0; /* 1 = got an escape, 2 = got escape followed
221 * by [, 0 = not doing any special processing.
222 * This is to handle special function keys. */
223
224 while ( (c = getchar() ) != EOF) {
225 if (c == 0x1b) {
226 /* got ESC, could be a special function key */
227 special = 1;
228 continue;
229 }
230 else if (special == 1 && c == '[') {
231 /* got ESC-[ */
232 special = 2;
233 continue;
234 }
235 else if (special == 2) {
236 /* map special functions to their equivalent commands */
237 if (c == '5') {
238 if ((c = getchar()) == '~') {
239 c = 'p'; /* Page Up key ==> previous */
240 }
241 }
242 else if (c == '6') {
243 if ((c = getchar()) == '~') {
244 c = 'n'; /* Page Down key ==> next */
245 }
246 }
247 else if (c == 'A') {
248 c = 'b'; /* Up key ==> backwards */
249 }
250 else if (c == 'B') {
251 c = 'f'; /* Down key ==> forwards */
252 }
253 }
254 special = 0;
255 do_cmd(c);
256 }
257}
258\f
259
260/* Error handler.
261 * For now just beep. Maybe eventually pop up an error message */
262
263void
264vgalib_error(msg)
265
266char *msg;
267
268{
269 (void) ioctl(Console, KDMKTONE, (150L << 16) | 3600L);
270}
271\f
272
273/* overlay a raster centered on the window */
274
275void
276vgalib_raster(bitmap, width, height)
277
278unsigned char *bitmap; /* what to display */
279int width, height; /* of bitmap, width is in bytes */
280
281{
282 int i, j;
283 int x, y; /* upper left corner of where to put bitmap,
284 * x in bytes */
285 unsigned char vbuff[BPL * 8];
286 int mask;
287 int byte;
288 int jx8; /* j times 8 */
289 int width8; /* width times 8 */
290 int ixwidth; /* i times width */
291
292
293 /* figure out how to center on screen */
294 x = ((BYTES_PER_LINE - width) / 2) * 8;
295 y = (Conf_info_p->vlines - height) / 2;
296
297 /* width translating bits to bytes */
298 width8 = width << 3;
299
300 /* copy bitmap to screen */
301 for (i = 0; i < height; i++) {
302 memset(vbuff, 0, width8);
303 ixwidth = i * width;
304
305 for (j = 0; j < width; j++) {
306 byte = bitmap [ ixwidth + j ];
307 jx8 = j << 3;
308 for (mask = 0; mask < 8; mask++) {
309 if (byte & (0x80 >> mask)) {
310 vbuff[jx8 + mask] = 0xf;
311 }
312 }
313 }
314 vga_drawscansegment(vbuff, x, y + i, width8);
315 }
316}
317\f
318
319/* put keyboard in raw mode */
320/* ported without change from the AT386 version. */
321
322static void
323setup_keyboard()
324
325{
326 struct termio ttyinfo;
327
328
329 if (isatty(0) != 1) {
330 (void) fprintf(stderr, "stdin is not a tty\n");
331 generalcleanup(1);
332 }
333
334 if (ioctl(0, TCGETA, &ttyinfo) < 0) {
335 (void) fprintf(stderr, "failed to get tty info\n");
336 generalcleanup(1);
337 }
338
339 /* turn off echo and canonical */
340 ttyinfo.c_lflag &= ~(ICANON | ECHO);
341 ttyinfo.c_cc[VMIN] = 1;
342 ttyinfo.c_cc[VTIME] = 3;
343 if (ioctl(0, TCSETA, &ttyinfo) < 0) {
344 (void) fprintf(stderr,
345 "failed to set keyboard modes, errno %d\n", errno);
346 generalcleanup(1);
347 }
348}
349\f
350
351#else
352
353/* some compilers complain about files that are effectively empty,
354 * so put in something even when entire file is effectively ifdef-ed out */
355static short dummy;
356
357#endif