chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mupdisp / linvga.c
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
31 int Orig_video_mode;
32 struct termio Orig_ttyinfo;     /* to put keyboard back from raw mode */
33 unsigned char Savefont[8192];   /* to put font back when we are done */
34 int Console;
35
36 static char *explanation =
37 "\n\
38 Note: The libvga used by this program\n\
39 requires write permissions to /dev/console.\n\
40 \n\
41 The best way to enable that is to do the following (as root):\n\
42 \tchown root mupdisp\n\
43 \tchmod 4755 mupdisp\n\
44 This makes mupdisp \"set user id\" to root.\n\
45 \n\
46 An alternate method would be to make /dev/console writeable by all:\n\
47 \tchmod 666 /dev/console\n\
48 but that method would pose a security risk, so it is not recommended.\n\n";
49 static void setup_keyboard P((void));
50 static void fix_keyboard P((void));
51 \f
52
53 /* set up for svgalib. Put video and keyboard in proper mode */
54
55 void
56 vgalib_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
109 void
110 vgalib_draw(line, small)
111
112 int line;       /* draw starting from this raster line of page */
113 int 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
184 void
185 vgalib_cleanup(status)
186
187 int 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
204 static void
205 fix_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
215 void
216 vgalib_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
263 void
264 vgalib_error(msg)
265
266 char *msg;
267
268 {
269         (void) ioctl(Console, KDMKTONE, (150L << 16) | 3600L);
270 }
271 \f
272
273 /* overlay a raster centered on the window */
274
275 void
276 vgalib_raster(bitmap, width, height)
277
278 unsigned char *bitmap;  /* what to display */
279 int 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
322 static void
323 setup_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 */
355 static short dummy;
356
357 #endif