Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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