1 /* Copyright (C) 1992, 1994, 1998 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: gdev3b1.c,v 1.2.6.1.2.1 2003/01/17 00:49:00 giles Exp $*/
20 /*
21 * This is a driver for the AT&T 3b1/7300/UnixPC console display.
22 *
23 * The image is built in a buffer the size of the page. Once complete,
24 * a screen-sized subset is copied to the screen, and one can scroll
25 * through the entire image (move with "vi" or arrow keys).
26 *
27 * Written by Andy Fyfe, andy@cs.caltech.edu.
28 *
29 * There are a couple of undesirable "features" that I have found no
30 * way to work around.
31 *
32 * 1) Gs attempts to save the contents of the window before using it, and
33 * then restores the contents afterward. However, if the gs window is
34 * not the current window, and there are small windows present, then
35 * the saved image is incorrect, and thus the screen will not be correctly
36 * restored. This seems to be a bug in the 3b1 window driver. Making
37 * the gs window current before saving its contents is not an acceptable
38 * solution.
39 *
40 * 2) Gs will enable the scrolling/help/cancel icons if the window has
41 * a border. Changing these border icons has the side effect of making
42 * the gs window current. This does circumvent the first problem though.
43 */
44
45 /*
46 * About the ATT3B1_PERF flag (notes by Andy Fyfe):
47 *
48 * I am unable to profile gs on the 3b1, so I added ATT3B1_PERF as a
49 * quick way to find out how much time was spent in the 3b1 driver,
50 * through dynamically suppressing parts of the code at run time by
51 * setting environment variables. I can then get the time spent in
52 * those parts by comparing the results of "time gs ....".
53 *
54 * At one point this was very useful, and led to a fairly substantial
55 * speedup of the fill and copy_mono routines. It also showed that I
56 * wasn't going to get too much more, overall, by further attempts to
57 * optimize the 3b1 driver. So those parts of the code controlled by
58 * ATT3B1_PERF have really now outlived their usefulness.
59 */
60
61 #include "gx.h"
62 #include "gxdevice.h"
63 #include "gserrors.h"
64
65 #include <errno.h>
66 #include <sys/window.h>
67 #include <sys/termio.h>
68
69 typedef struct gx_device_att3b1_s {
70 gx_device_common;
71 int fd; /* window file descriptor */
72 uchar *screen; /* pointer to screen image */
73 ushort line_size; /* size of screen line in bytes */
74 ulong screen_size; /* size of screen image in bytes */
75 int page_num; /* page number */
76 #ifdef ATT3B1_PERF
77 char *no_output, *no_fill, *no_copy;
78 #endif
79 } gx_device_att3b1;
80 #define att3b1dev ((gx_device_att3b1 *)dev)
81
82 #define XDPI 100 /* to get a more-or-less square aspect ratio */
83 #define YDPI 72
84 #define XSIZE (8.5 * XDPI) /* 8.5 x 11 inch page, by default */
85 #define YSIZE (11 * YDPI)
86
87 static const ushort masks[] = { 0,
88 0x0001, 0x0003, 0x0007, 0x000f,
89 0x001f, 0x003f, 0x007f, 0x00ff,
90 0x01ff, 0x03ff, 0x07ff, 0x0fff,
91 0x1fff, 0x3fff, 0x7fff, 0xffff,
92 };
93 static uchar reverse_bits[256] = {
94 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
95 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
96 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
97 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
98 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
99 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
100 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
101 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
102 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
103 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
104 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
105 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
106 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
107 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
108 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
109 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
110 };
111
112 dev_proc_open_device(att3b1_open);
113 dev_proc_close_device(att3b1_close);
114 dev_proc_fill_rectangle(att3b1_fill_rectangle);
115 dev_proc_copy_mono(att3b1_copy_mono);
116 dev_proc_output_page(att3b1_output_page);
117
118 private gx_device_procs att3b1_procs = {
119 att3b1_open,
120 gx_default_get_initial_matrix,
121 gx_default_sync_output,
122 att3b1_output_page,
123 att3b1_close,
124 gx_default_map_rgb_color,
125 gx_default_map_color_rgb,
126 att3b1_fill_rectangle,
127 gx_default_tile_rectangle,
128 att3b1_copy_mono,
129 gx_default_copy_color,
130 gx_default_draw_line,
131 gx_default_get_bits
132 };
133
134 gx_device_att3b1 gs_att3b1_device = {
135 std_device_std_body(gx_device_att3b1, &att3b1_procs, "att3b1",
136 XSIZE, YSIZE, XDPI, YDPI),
137 { 0 }, /* std_procs */
138 -1, 0, 0, /* fd, screen, line_size, */
139 0, 0, /* screen size, page */
140 #ifdef ATT3B1_PERF
141 0, 0, 0, /* no_output, no_fill, no_copy */
142 #endif
143 };
144
145 int
att3b1_open(gx_device * dev)146 att3b1_open(gx_device *dev)
147 {
148 struct uwdata uw;
149
150 #ifdef ATT3B1_PERF
151 char *getenv(const char *);
152 #endif
153
154 if (att3b1dev->fd >= 0) {
155 close(att3b1dev->fd);
156 att3b1dev->fd = -1;
157 }
158
159 if (att3b1dev->screen != NULL) {
160 gs_free((char *)att3b1dev->screen,
161 att3b1dev->screen_size, 1, "att3b1_open");
162 att3b1dev->screen = 0;
163 att3b1dev->screen_size = 0;
164 }
165
166 att3b1dev->fd = open("/dev/tty", 2);
167 if (att3b1dev->fd < 0) {
168 lprintf1("att3b1_open: open /dev/tty failed [%d]\n", errno);
169 return_error(gs_error_ioerror);
170 }
171
172 /* Verify that /dev/tty is associated with a console window. */
173 if (ioctl(att3b1dev->fd, WIOCGETD, &uw) < 0) {
174 lprintf1("att3b1_open: can not obtain window data [%d]\n", errno);
175 lprintf("att3b1_open: the att3b1 device requires a console window\n");
176 att3b1_close(dev);
177 return_error(gs_error_ioerror);
178 }
179
180 /* we need an even number of bytes per line */
181 att3b1dev->line_size = ((att3b1dev->width + 15) / 16) * 2;
182 att3b1dev->screen_size = att3b1dev->line_size * att3b1dev->height;
183
184 att3b1dev->screen =
185 (uchar *)gs_malloc(att3b1dev->screen_size, 1, "att3b1_open");
186 if (att3b1dev->screen == NULL) {
187 att3b1_close(dev);
188 return_error(gs_error_VMerror);
189 }
190
191 att3b1dev->page_num = 1;
192
193 #ifdef ATT3B1_PERF
194 att3b1dev->no_output = getenv("GS_NOOUTPUT");
195 att3b1dev->no_fill = getenv("GS_NOFILL");
196 att3b1dev->no_copy = getenv("GS_NOCOPY");
197 #endif
198
199 return 0;
200 }
201
202 int
att3b1_close(gx_device * dev)203 att3b1_close(gx_device *dev)
204 {
205 if (att3b1dev->fd >= 0) {
206 close(att3b1dev->fd);
207 att3b1dev->fd = -1;
208 }
209
210 if (att3b1dev->screen != NULL) {
211 gs_free((char *)att3b1dev->screen,
212 att3b1dev->screen_size, 1, "att3b1_close");
213 att3b1dev->screen = 0;
214 att3b1dev->screen_size = 0;
215 }
216
217 return 0;
218 }
219
220 int
att3b1_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index colour)221 att3b1_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
222 gx_color_index colour)
223 {
224 uint o, b, wl, wr, w2;
225 ushort *p, *q, maskl, maskr;
226
227 #ifdef ATT3B1_PERF
228 if (att3b1dev->no_fill) return 0;
229 #endif
230
231 fit_fill(dev, x, y, w, h);
232
233 /* following fit_fill, we can assume x, y, w, h are unsigned. */
234
235 p = (ushort *)&att3b1dev->screen[(ushort)y*att3b1dev->line_size] +
236 (uint)x/16;
237 o = (uint)x % 16;
238 b = 16 - o;
239 wl = ((uint)w < b) ? (uint)w : b;
240 maskl = masks[wl] << o;
241 w -= wl;
242 wr = (uint)w % 16;
243 maskr = masks[wr];
244
245 if (colour == 0) {
246 maskl = ~maskl;
247 maskr = ~maskr;
248 while (h-- > 0) {
249 q = p;
250 w2 = w;
251 *q++ &= maskl;
252 while (w2 >= 16) {
253 *q++ = 0;
254 w2 -= 16;
255 }
256 *q &= maskr;
257 p += (att3b1dev->line_size / 2);
258 }
259 }
260 else {
261 while (h-- > 0) {
262 q = p;
263 w2 = w;
264 *q++ |= maskl;
265 while (w2 >= 16) {
266 *q++ = 0xffff;
267 w2 -= 16;
268 }
269 *q |= maskr;
270 p += (att3b1dev->line_size / 2);
271 }
272 }
273
274 return 0;
275 }
276
277 #ifdef __GNUC__
278 #define rotate(value, count) \
279 asm("ror%.l %2,%0" : "=d" (value) : "0" (value), "d" (count))
280 #else
281 #define rotate(value, count) \
282 value = (value >> count) | (value << (32-count))
283 #endif
284
285 int
att3b1_copy_mono(gx_device * dev,const uchar * data,int data_x,int raster,gx_bitmap_id id,int x,int y,int width,int height,gx_color_index colour0,gx_color_index colour1)286 att3b1_copy_mono(gx_device *dev, const uchar *data,
287 int data_x, int raster, gx_bitmap_id id,
288 int x, int y, int width, int height,
289 gx_color_index colour0, gx_color_index colour1)
290 {
291 const ushort *src_p, *src_q;
292 ushort *dst_p, *dst_q;
293 ulong bits, mask, *p;
294 uint src_o, src_b, dst_o, dst_b, op;
295 uint w1, w2;
296
297 #ifdef ATT3B1_PERF
298 if (att3b1dev->no_copy) return 0;
299 #endif
300
301 if (colour1 == colour0) /* vacuous case */
302 return att3b1_fill_rectangle(dev, x, y, width, height, colour0);
303
304 fit_copy(dev, data, data_x, raster, id, x, y, width, height);
305
306 /* following fit_copy, we can assume x, y, width, height are unsigned. */
307
308 /*
309 * In what follows, we're assuming that each row of the input bitmap
310 * is short-aligned, that is, that both "data" and "raster" are even.
311 */
312 src_p = ((const ushort *)data) + (uint)data_x/16;
313 src_o = (uint)data_x % 16;
314 src_b = 16 - src_o;
315
316 dst_p = (ushort *)&att3b1dev->screen[(ushort)y*att3b1dev->line_size] +
317 (uint)x/16;
318 dst_o = (uint)x % 16;
319 dst_b = 16 - dst_o;
320
321 op = (int)colour0 * 3 + (int)colour1 + 4;
322
323 while (height-- > 0) {
324 w2 = width;
325 src_q = src_p;
326 dst_q = dst_p;
327
328 while (w2 > 0) {
329 w1 = (w2 < 16) ? w2 : 16;
330 mask = masks[w1];
331 /*
332 * We are assuming that the bitmap "data" is typically aligned.
333 * Thus the test for this special case is typically a win over
334 * a 16-bit shift.
335 */
336 if (src_o == 0)
337 bits = *src_q++;
338 else {
339 bits = *((ulong *)src_q) >> src_b;
340 bits &= 0xffff;
341 src_q++;
342 }
343 if (w1 <= 8)
344 bits = reverse_bits[bits>>8];
345 else
346 bits = (reverse_bits[bits&0xff] << 8) | reverse_bits[bits>>8];
347 /*
348 * While the input bit map is assumed to be typically aligned, we
349 * assume that the place in the image is not. Thus we don't
350 * separate out the aligned case. Doing so would cost a test,
351 * and only reduce the average shift by about 1.
352 */
353 p = (ulong *)dst_q;
354 switch(op) {
355 case 1: /* not src and dst */
356 bits = ~(bits & mask);
357 rotate(bits,dst_b);
358 *p &= bits;
359 break;
360 case 2: /* src or dst */
361 bits = bits & mask;
362 rotate(bits,dst_b);
363 *p |= bits;
364 break;
365 case 3: /* src and dst */
366 bits = bits | ~mask;
367 rotate(bits,dst_b);
368 *p &= bits;
369 break;
370 case 5: /* src */
371 rotate(bits,dst_b);
372 rotate(mask,dst_b);
373 *p = (*p & ~mask) | (bits & mask);
374 break;
375 case 6: /* not src or dst */
376 bits = ~bits & mask;
377 rotate(bits,dst_b);
378 *p |= bits;
379 break;
380 case 7: /* not src */
381 rotate(bits,dst_b);
382 rotate(mask,dst_b);
383 *p = (*p & ~mask) | (~bits & mask);
384 break;
385 }
386 dst_q++;
387 w2 -= w1;
388 }
389
390 src_p += (raster / 2);
391 dst_p += (att3b1dev->line_size / 2);
392 }
393
394 return 0;
395 }
396
397 static int getKeyboard(gx_device *);
398
399 const char *help_msg[] = {
400 "h, j, k, l, UP, DOWN, LEFT, RIGHT move the page (0.25\" h, 0.5\" v)",
401 "H, J, K, L, BEG, END move to far edge of the page",
402 "^U, ^D, ROLL UP, ROLL DOWN scroll up or down (1/2 screen height)",
403 "^F, ^B, PAGE UP, PAGE DOWN scroll up or down (full screen height)",
404 "c, C centre page horizontally, vertically",
405 "<, >, ^, _ fine movements (single pixel)",
406 "^L, ^R, r, HOME move to default position",
407 "=, MARK make current position the default",
408 "I invert the image (black <-> white)",
409 "q, x, ^C, EXIT, CANCL, n, f, NEXT,",
410 " SPACE, RETURN, ENTER end the page",
411 "?, HELP help screen",
412 };
413
414 static void
do_help(gx_device * dev)415 do_help(gx_device *dev)
416 {
417 int i;
418 struct utdata ut;
419
420 /* we would like to save the cursor position, but we can't */
421 write(att3b1dev->fd, "\033[2J\033[H", 7);
422
423 /* write help screen */
424 for (i=0; i < sizeof(help_msg)/sizeof(help_msg[0]); ++i) {
425 write(att3b1dev->fd, help_msg[i], strlen(help_msg[i]));
426 write(att3b1dev->fd, "\n", 1);
427 }
428 ut.ut_num = WTXTSLK1;
429 strcpy(ut.ut_text, "Press any key to continue");
430 ioctl(att3b1dev->fd, WIOCSETTEXT, &ut);
431
432 /* wait for keyboard input */
433 i = getKeyboard(dev);
434
435 /* clear screen and put cursor at the bottom of the screen */
436 write(att3b1dev->fd, "\033[2J\033[99;1H", 11);
437 }
438
439 private int
att3b1_do_output_page(gx_device * dev,int num_copies,int flush)440 att3b1_do_output_page(gx_device *dev, int num_copies, int flush)
441 {
442 struct urdata ur;
443 struct utdata ut, ut_orig;
444 struct uwdata uw;
445 int uflags;
446 struct termio old, new;
447 int xorigin, yorigin;
448 static int def_xorigin = 0, def_yorigin = 0;
449 int screen_width, screen_height;
450 int inverted = 0;
451 int error = 0;
452 int ch;
453 ushort *p;
454 ushort save_image[WINWIDTH * WINHEIGHT / 16];
455
456 #ifdef ATT3B1_PERF
457 if (att3b1dev->no_output) return 0;
458 #endif
459
460 /*
461 * initialize, and save screen state
462 */
463
464 if (ioctl(att3b1dev->fd, WIOCGETD, &uw) < 0) {
465 lprintf1("att3b1_output_page: window WIOCGETD ioctl failed [%d]\n",
466 errno);
467 att3b1_close(dev);
468 return_error(gs_error_ioerror);
469 }
470
471 /*
472 * we assume, henceforth, that screen ioctl calls will succeed
473 */
474
475 write(att3b1dev->fd, "\a\033[=1C", 6);
476
477 uflags = uw.uw_uflags;
478 if (!(uflags & NBORDER)) {
479 uw.uw_uflags = BORDHSCROLL | BORDVSCROLL | BORDHELP | BORDCANCEL;
480 ioctl(att3b1dev->fd, WIOCSETD, &uw);
481 }
482
483 ut_orig.ut_num = WTXTSLK1;
484 ioctl(att3b1dev->fd, WIOCGETTEXT, &ut_orig);
485
486 /* This isn't necessary, but helps a bit when the following attempt
487 to get the current screen image fails (without any indication). */
488 memset(save_image, '\0', sizeof(save_image));
489
490 ur.ur_srcbase = 0;
491 ur.ur_srcwidth = 0;
492 ur.ur_srcx = 0;
493 ur.ur_srcy = 0;
494 ur.ur_dstbase = save_image;
495 ur.ur_dstwidth = WINWIDTH / 8;
496 ur.ur_dstx = 0;
497 ur.ur_dsty = 0;
498 ur.ur_width = uw.uw_width;
499 ur.ur_height = uw.uw_height;
500 ur.ur_srcop = SRCSRC;
501 ur.ur_dstop = DSTSRC;
502 ur.ur_pattern = 0;
503 ioctl(att3b1dev->fd, WIOCRASTOP, &ur);
504
505 ioctl(att3b1dev->fd, TCGETA, &old);
506 new = old;
507 new.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
508 new.c_cc[VMIN] = 1;
509 ioctl(att3b1dev->fd, TCSETAF, &new);
510
511 screen_width = (uw.uw_width < att3b1dev->width) ? uw.uw_width
512 : att3b1dev->width;
513 screen_height = (uw.uw_height < att3b1dev->height) ? uw.uw_height
514 : att3b1dev->height;
515
516 write(att3b1dev->fd, "\033[2J", 4);
517
518 ur.ur_srcwidth = att3b1dev->line_size;
519 ur.ur_width = screen_width;
520 ur.ur_height = screen_height;
521 ur.ur_dstbase = 0;
522 ur.ur_dstwidth = 0;
523
524 /*
525 * allow one to move the screen window through the entire image
526 */
527
528 xorigin = def_xorigin;
529 yorigin = def_yorigin;
530
531 while (1) {
532 /* Things go bad if ur_srcx >= 2048 */
533 ur.ur_srcbase = (ushort *)att3b1dev->screen + (xorigin >> 4);
534 ur.ur_srcx = xorigin & 15;
535 ur.ur_srcy = yorigin;
536
537 if (ioctl(att3b1dev->fd, WIOCRASTOP, &ur) < 0) {
538 lprintf1(
539 "att3b1_output_page: window WIOCRASTOP ioctl failed [%d]\n",
540 errno);
541 error = gs_error_ioerror;
542 }
543
544 ut.ut_num = WTXTSLK1;
545 sprintf(ut.ut_text,
546 "%s %d, top right (%d,%d), size (%d,%d), press '?' for help.",
547 flush ? "Showpage" : "Copypage", att3b1dev->page_num, xorigin, yorigin,
548 att3b1dev->width, att3b1dev->height);
549 ioctl(att3b1dev->fd, WIOCSETTEXT, &ut);
550
551 ch = error ? 'q' : getKeyboard(dev);
552
553 switch(ch) {
554 case 'h':
555 xorigin -= ((uint)(int)att3b1dev->x_pixels_per_inch+3)/4;
556 break;
557
558 case 'k':
559 yorigin -= ((uint)(int)att3b1dev->y_pixels_per_inch+1)/2;
560 break;
561
562 case 'l':
563 xorigin += ((uint)(int)att3b1dev->x_pixels_per_inch+3)/4;
564 break;
565
566 case 'j':
567 yorigin += ((uint)(int)att3b1dev->y_pixels_per_inch+1)/2;
568 break;
569
570 case 'H':
571 xorigin = 0;
572 break;
573
574 case 'K':
575 yorigin = 0;
576 break;
577
578 case 'L':
579 xorigin = att3b1dev->width - screen_width;
580 break;
581
582 case 'J':
583 yorigin = att3b1dev->height - screen_height;
584 break;
585
586 case '<':
587 xorigin -= 1;
588 break;
589
590 case '>':
591 xorigin += 1;
592 break;
593
594 case '^':
595 yorigin -= 1;
596 break;
597
598 case '_':
599 yorigin += 1;
600 break;
601
602
603 case '\025': /* control-U */
604 yorigin -= screen_height/2;
605 break;
606
607 case '\004': /* control-D */
608 yorigin += screen_height/2;
609 break;
610
611 case '\002': /* control-B */
612 yorigin -= screen_height;
613 break;
614
615 case '\006': /* control-F */
616 yorigin += screen_height;
617 break;
618
619 case '\f':
620 case 'r' :
621 case '\022': /* control-R */
622 xorigin = def_xorigin;
623 yorigin = def_yorigin;
624 break;
625
626 case 'c': /* centre horizontally */
627 xorigin = (att3b1dev->width - screen_width) / 2;
628 break;
629
630 case 'C': /* centre vertically */
631 yorigin = (att3b1dev->height - screen_height) / 2;
632 break;
633
634 case '=':
635 def_xorigin = xorigin;
636 def_yorigin = yorigin;
637 break;
638
639 case 'I':
640 for (p = (ushort *)att3b1dev->screen;
641 p < (ushort *)&att3b1dev->screen[att3b1dev->screen_size]; ++p)
642 *p = ~ *p;
643 inverted = !inverted;
644 break;
645
646 case '?':
647 do_help(dev);
648 break;
649
650 case -1:
651 error = gs_error_ioerror;
652 /* fall through, for cleanup */
653
654 case 'q':
655 case 'x':
656 case '\003': /* control-C */
657 case 'n':
658 case 'f':
659 case ' ':
660 case '\n':
661 case '\r':
662 if (flush)
663 att3b1dev->page_num++;
664 else if (inverted) /* restore inverted image for copypage */
665 for (p = (ushort *)att3b1dev->screen;
666 p < (ushort *)&att3b1dev->screen[att3b1dev->screen_size]; ++p)
667 *p = ~ *p;
668 if (!(uflags & NBORDER)) {
669 ioctl(att3b1dev->fd, WIOCGETD, &uw); /*window may have moved*/
670 uw.uw_uflags = uflags;
671 ioctl(att3b1dev->fd, WIOCSETD, &uw);
672 }
673 ur.ur_srcbase = save_image;
674 ur.ur_srcwidth = WINWIDTH / 8;
675 ur.ur_width = uw.uw_width;
676 ur.ur_height = uw.uw_height;
677 ur.ur_srcx = 0;
678 ur.ur_srcy = 0;
679 ioctl(att3b1dev->fd, WIOCRASTOP, &ur);
680 ioctl(att3b1dev->fd, WIOCSETTEXT, &ut_orig);
681 ioctl(att3b1dev->fd, TCSETAF, &old);
682 write(att3b1dev->fd, "\033[=0C", 5);
683
684 if (error) {
685 att3b1_close(dev);
686 return_error(error);
687 }
688 else
689 return 0;
690 }
691
692 if (xorigin >= att3b1dev->width - screen_width)
693 xorigin = att3b1dev->width - screen_width;
694 if (xorigin < 0)
695 xorigin = 0;
696 if (yorigin >= att3b1dev->height - screen_height)
697 yorigin = att3b1dev->height - screen_height;
698 if (yorigin < 0)
699 yorigin = 0;
700 }
701 }
702 int
att3b1_output_page(gx_device * dev,int num_copies,int flush)703 att3b1_output_page(gx_device *dev, int num_copies, int flush)
704 {
705 int code = att3b1_do_output_page(dev, num_copies, flush);
706
707 if (code >= 0)
708 code = gx_finish_output_page(dev, num_copies, flush);
709 return code;
710 }
711
712 static int
get_char(gx_device * dev)713 get_char(gx_device *dev)
714 {
715 char ch;
716 int count;
717
718 count = read(att3b1dev->fd, &ch, 1);
719 if (count == 0)
720 return 'q';
721 else if (count < 0)
722 return -1;
723 else
724 return ch;
725 }
726
727 static int
getKeyboard(gx_device * dev)728 getKeyboard(gx_device *dev)
729 {
730 char ch;
731
732 ch = get_char(dev);
733
734 if (ch != '\033')
735 return ch;
736
737 /*
738 * If the char is escape, interpret the escape sequence and return
739 * an equivalent single character.
740 *
741 * Note that a mouse click on a window border icon is translated
742 * to the corresponding key, for example, the "up" icon generates
743 * roll-up/page-up/beg for the left/middle/right mouse button.
744 */
745
746 switch (get_char(dev)) {
747 case '[':
748 switch(get_char(dev)) {
749 case 'A': /* up arrow */
750 return 'k';
751 case 'T': /* shift up arrow (roll up) */
752 return '\025';
753 case 'B': /* down arrow */
754 return 'j';
755 case 'S': /* shift down arrow (roll down) */
756 return '\004';
757 case 'C': /* right arrow */
758 return 'l';
759 case 'D': /* left arrow */
760 return 'h';
761 case 'H': /* home */
762 return 'r';
763 case 'U': /* page down */
764 return '\006';
765 case 'V': /* page up */
766 return '\002';
767 }
768 break;
769 case 'O':
770 switch(get_char(dev)) {
771 case 'm': /* help */
772 case 'M': /* shift help */
773 return '?';
774 case 'k': /* exit */
775 case 'K': /* shift exit */
776 case 'w': /* cancl */
777 case 'W': /* shift cancl */
778 return 'q';
779 }
780 break;
781 case 'N':
782 switch(get_char(dev)) {
783 case 'h': /* next */
784 return 'f';
785 case 'i': /* mark */
786 return '=';
787 case 'L': /* shift right arrow */
788 return 'l';
789 case 'K': /* shift left arrow */
790 return 'h';
791 }
792 break;
793 case '9': /* Beg */
794 return 'K';
795 case '0': /* End */
796 return 'J';
797 }
798 return '\0';
799 }
800