2 /* Copyright (c) 1997, 1998, 1999, 2000, 2002 by Arkkra Enterprises */
3 /* All rights reserved */
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 ;-)
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:
18 #if defined(linux) && ! defined(NO_VGA_LIB)
27 #include <sys/ioctl.h>
29 #define BPL (80) /* bytes per line on screen */
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 */
36 static char *explanation
=
38 Note: The libvga used by this program\n\
39 requires write permissions to /dev/console.\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\
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));
53 /* set up for svgalib. Put video and keyboard in proper mode */
59 register int n
; /* for setting signal catching */
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");
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. */
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
);
80 if (ioctl(Console
, GIO_FONT
, Savefont
) < 0) {
81 (void) fprintf(stderr
, "unable to save console font\n");
87 /* get current video mode, so we can put it back when we're done */
88 Orig_video_mode
= vga_getcurrentmode();
90 /* make sure we always clean up, so user isn't left stuck in raw and/or
92 for (n
= 1; n
< NSIG
; n
++) {
93 if ( n
!= SIGKILL
&& n
!= SIGCLD
) {
94 (void) signal(n
, Conf_info_p
->cleanup
);
97 (void) signal(SIGWINCH
, SIG_IGN
);
99 /* put keyboard into raw mode */
102 /* put screen into graphics mode */
103 vga_setmode(G640x480x16
);
107 /* draw stuff onto screen. Draw starting at specified line of page */
110 vgalib_draw(line
, small
)
112 int line
; /* draw starting from this raster line of page */
113 int small
; /* YES if should draw small view of full page */
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) */
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");
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
);
139 /* vgalib wants 1 byte per pixel, we have 1 bit per pixel,
140 * so multiply by 8 */
141 vbytes
= BYTES_PER_LINE
<< 3;
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
);
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
;
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);
159 /* transfer bitmap row to vbuff, 1 bit of bitmap to 1 byte
161 for (j
= 0; j
< BYTES_PER_LINE
; j
++) {
162 /* get j times 8 bits per byte */
165 /* for each black bit, set appropriate
167 for (mask
= 0; mask
< 8; mask
++) {
168 if (buff
[j
] & (0x80 >> mask
)) {
169 vbuff
[jx8
+ mask
] = 0;
174 /* display this line */
175 vga_drawscanline(i
, vbuff
);
181 * Put screen back into previous mode.
185 vgalib_cleanup(status
)
190 /* put video back to normal */
191 vga_setmode(Orig_video_mode
);
192 (void) ioctl(Console
, PIO_FONT
, Savefont
);
195 /* put keyboard back to normal */
196 (void) ioctl(0, TCSETA
, &Orig_ttyinfo
);
198 /* call the non-terminal-type specific cleanup */
199 generalcleanup(status
);
202 /* some versions of vgalib seem to put things into noecho mode. So undo that. */
207 (void) ioctl(0, TCSETA
, &Orig_ttyinfo
);
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() */
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. */
224 while ( (c
= getchar() ) != EOF
) {
226 /* got ESC, could be a special function key */
230 else if (special
== 1 && c
== '[') {
235 else if (special
== 2) {
236 /* map special functions to their equivalent commands */
238 if ((c
= getchar()) == '~') {
239 c
= 'p'; /* Page Up key ==> previous */
243 if ((c
= getchar()) == '~') {
244 c
= 'n'; /* Page Down key ==> next */
248 c
= 'b'; /* Up key ==> backwards */
251 c
= 'f'; /* Down key ==> forwards */
261 * For now just beep. Maybe eventually pop up an error message */
269 (void) ioctl(Console
, KDMKTONE
, (150L << 16) | 3600L);
273 /* overlay a raster centered on the window */
276 vgalib_raster(bitmap
, width
, height
)
278 unsigned char *bitmap
; /* what to display */
279 int width
, height
; /* of bitmap, width is in bytes */
283 int x
, y
; /* upper left corner of where to put bitmap,
285 unsigned char vbuff
[BPL
* 8];
288 int jx8
; /* j times 8 */
289 int width8
; /* width times 8 */
290 int ixwidth
; /* i times width */
293 /* figure out how to center on screen */
294 x
= ((BYTES_PER_LINE
- width
) / 2) * 8;
295 y
= (Conf_info_p
->vlines
- height
) / 2;
297 /* width translating bits to bytes */
300 /* copy bitmap to screen */
301 for (i
= 0; i
< height
; i
++) {
302 memset(vbuff
, 0, width8
);
305 for (j
= 0; j
< width
; j
++) {
306 byte
= bitmap
[ ixwidth
+ j
];
308 for (mask
= 0; mask
< 8; mask
++) {
309 if (byte
& (0x80 >> mask
)) {
310 vbuff
[jx8
+ mask
] = 0xf;
314 vga_drawscansegment(vbuff
, x
, y
+ i
, width8
);
319 /* put keyboard in raw mode */
320 /* ported without change from the AT386 version. */
326 struct termio ttyinfo
;
329 if (isatty(0) != 1) {
330 (void) fprintf(stderr
, "stdin is not a tty\n");
334 if (ioctl(0, TCGETA
, &ttyinfo
) < 0) {
335 (void) fprintf(stderr
, "failed to get tty info\n");
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
);
353 /* some compilers complain about files that are effectively empty,
354 * so put in something even when entire file is effectively ifdef-ed out */