mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (08/25/89)
Submitted-by: ecn!jack@nluug.nl (Jack van Wijk) Posting-number: Volume 1, Issue 59 Archive-name: looking-glass I submit the following tool for the comp.sources.sun group. It is a looking-glass, which enables the user to look at the screen in detail. In my opinion, it is better (more features) and faster than the old glass (in the SUN User Group 87 tapes). With compliments, Jack van Wijk ---------- Netherlands Energy Research Foundation, ECN -------------- Jack (Jarke J.) van Wijk UUCP : jack@ecn.uucp P.O. Box 1, 1755 ZG Petten(NH) ARPA : ecn!jack@nluug.nl Holland phone: +31 2246 4333 ecn!jack@uunet.uu.net --------------------------------------------------------------------------- : To unbundle, sh this file echo README cat >README <<'@@@ End of README' Lglass is a SunView tool for looking at the screen. Options are: user-selectable scale, color/bw, dynamic update, and dragging. To make this tool, just type make. @@@ End of README echo Makefile cat >Makefile <<'@@@ End of Makefile' WINLIBS = -lsuntool -lsunwindow -lpixrect lglass: lglass.o show.o cc -o $@ $(CFLAGS) lglass.o show.o $(WINLIBS) @@@ End of Makefile echo lglass.c cat >lglass.c <<'@@@ End of lglass.c' /************************************************************************* Lglass: screen viewer for the Sun Workstation running SunView Copyright (c) 1989 by Jack van Wijk 7/24/89 @ Netherlands Energy Research Foundation, ECN This program may be redistributed without fee as long as this copyright notice is intact. ---------- Netherlands Energy Research Foundation, ECN ------------------ Jack (Jarke J.) van Wijk UUCP : jack@ecn.uucp P.O. Box 1, 1755 ZG Petten(NH) ARPA : ecn!jack@nluug.nl Holland phone: +31 2246 4333 ecn!jack@uunet.uu.net *************************************************************************/ #include <stdio.h> #include <sys/time.h> #include <suntool/sunview.h> #include <suntool/window.h> #include <suntool/panel.h> #include <suntool/canvas.h> #define MAXSCALE 32 #define SCALESTRINGS "1", "2", "4", "8", "16", "32" #define SCALEMENUSTRINGS "zoom in", "zoom out" #define UPDATEMENUSTRINGS "off", "slow", "fast" #define COLORSTRINGS "B/W", "color" Pixrect *scr_pr; Frame my_frame; Canvas my_canvas; Panel_item scale_item; Cursor std_cursor, select_cursor; struct { int depth; int scale; int curx; int cury; } GV = { 1, 1, 500, 500 }; short select_data[] = { #include "select.cursor" }; mpr_static (select_pr, 16, 16, 1, select_data); short glas_data[] = { #include "lglass.icon" }; mpr_static (glas_pr, 64, 64, 1, glas_data); /*----------------------------------------------------------------------*/ scale_to_nr(scale) /* Map scale to number: 2**nr = scale */ int scale; { int nr; for (nr= 0; scale > 1; scale /=2) nr++; return nr; } /*----------------------------------------------------------------------*/ nr_to_scale(nr) /* Map number to scale : 2**nr = scale */ int nr; { int scale; for (scale = 1; nr > 0; nr--) scale *= 2; return scale; } /*----------------------------------------------------------------------*/ do_repaint() { if (!window_get(my_frame, FRAME_CLOSED)) { show_pic(GV.curx, GV.cury, GV.scale); } } /*----------------------------------------------------------------------*/ do_select(window, event, arg) Window window; Event *event; caddr_t arg; { static int lx, ly, dragging = 0; int dx, dy, value, i; static Menu scale_menu = NULL; dx = (event_x(event) - (int) window_get(window, WIN_WIDTH )/2) /GV.scale; dy = (event_y(event) - (int) window_get(window, WIN_HEIGHT)/2) /GV.scale; switch (event_id(event)) { case MS_LEFT: if (event_is_up(event)) show_pic(GV.curx+dx, GV.cury+dy, GV.scale); break; case MS_MIDDLE: if (event_is_down(event)) { lx = dx; ly = dy; dragging = 1; } else dragging = 0; break; case LOC_MOVE: case LOC_DRAG: if (!dragging) break; show_pic(GV.curx+lx-dx, GV.cury+ly-dy, GV.scale); lx = dx; ly = dy; break; case MS_RIGHT: scale_menu = menu_create(MENU_STRINGS, SCALEMENUSTRINGS, 0, 0); value = (int) menu_show(scale_menu, window, event, 0); if (value == 0) return; if (value == 1 && GV.scale < MAXSCALE) GV.scale *= 2; else if (value == 2 && GV.scale > 1) GV.scale /= 2; else return; panel_set_value(scale_item, scale_to_nr(GV.scale)); show_pic(GV.curx+dx, GV.cury+dy, GV.scale); break; } } /*----------------------------------------------------------------------*/ do_set_scale(item, value, event) Panel_item item; int value; Event *event; { show_pic(GV.curx, GV.cury, nr_to_scale(value)); } /*----------------------------------------------------------------------*/ do_set_color(item, value, event) Panel_item item; int value; Event *event; { if (value == 0) GV.depth = 1; else GV.depth = 8; window_set(my_canvas, CANVAS_FAST_MONO, (GV.depth == 1 ? TRUE : FALSE), 0); reset_plane_groups(); reset_colortable(); do_repaint(); } #define ITIMER_NULL ((struct itimerval *) NULL) /*----------------------------------------------------------------------*/ do_set_update(item, value, event) Panel_item item; int value; Event *event; { static int my_client_object; static int *my_client = &my_client_object; struct itimerval timerval; if (value == 0) notify_set_itimer_func(my_client, do_repaint, ITIMER_REAL, NULL, ITIMER_NULL); else { timerval.it_value.tv_usec = 0; timerval.it_value.tv_sec = 1; if (value == 1) { timerval.it_interval.tv_usec = 0; timerval.it_interval.tv_sec = 1; } else { timerval.it_interval.tv_usec = 200; timerval.it_interval.tv_sec = 0; } do_repaint(); notify_set_itimer_func(my_client, do_repaint, ITIMER_REAL, &timerval, ITIMER_NULL); } } /*----------------------------------------------------------------------*/ do_done() { window_set(my_frame, FRAME_CLOSED, TRUE, 0); } /*----------------------------------------------------------------------*/ do_quit() { if (window_destroy(my_frame)) exit(0); } /*----------------------------------------------------------------------*/ reset_colortable() { #define CMS_NAME "GLASS_COLOUR" #define CMS_SIZE 256 u_char red[CMS_SIZE], green[CMS_SIZE], blue[CMS_SIZE]; Pixwin *pw; if (GV.depth > 1) { pw = canvas_pixwin(my_canvas); pr_getcolormap(scr_pr, 0, 256, red, green, blue); pw_setcmsname(pw, CMS_NAME); pw_putcolormap(pw, 0, CMS_SIZE, red, green, blue); } } /*----------------------------------------------------------------------*/ static void select_proc(window, event) Window window; Event *event; { static int dragging = 0; int cx, cy; switch (event_id(event)) { case MS_LEFT: if (event_is_down(event) || (event_is_up(event) && dragging > 5)) exit_grab(window, event); dragging = 0; break; case LOC_DRAG: dragging++; get_abs_pos(window, event_x(event), event_y(event), &cx, &cy); show_pic(cx, cy, GV.scale); break; default: panel_default_handle_event(window, event); break; } } /*----------------------------------------------------------------------*/ static void init_grab_proc(item, event) Panel_item item; Event *event; { Panel panel; if (event_action(event) == MS_LEFT && event_is_down(event)) { panel = (Window) panel_get(item, PANEL_PARENT_PANEL); window_set(panel, WIN_GRAB_ALL_INPUT, TRUE, WIN_EVENT_PROC, select_proc, WIN_CURSOR, select_cursor, 0); } } /*----------------------------------------------------------------------*/ exit_grab(window, event) Window window; Event *event; { int cx, cy; /* Disable grab all input and get look-up table */ window_set(window, WIN_GRAB_ALL_INPUT, FALSE, 0); reset_colortable(); /* Set std_cursor invisible, grab all input, and get image */ cursor_set(std_cursor, CURSOR_SHOW_CURSOR, FALSE, 0); window_set(window, WIN_GRAB_ALL_INPUT, TRUE, WIN_CURSOR, std_cursor, 0); get_abs_pos(window, event_x(event), event_y(event), &cx, &cy); show_pic(cx, cy, GV.scale); /* Set std_cursor visible, and reset grab all input */ cursor_set(std_cursor, CURSOR_SHOW_CURSOR, TRUE, 0); window_set(window, WIN_GRAB_ALL_INPUT, FALSE, WIN_EVENT_PROC, NULL, WIN_CURSOR, std_cursor, 0); } /*----------------------------------------------------------------------*/ show_pic(cx, cy, scale) int cx, cy; register int scale; { int dw, dh, dws, dhs; Pixwin *pw; pw = canvas_pixwin(my_canvas); dw = (int) window_get(my_canvas, WIN_WIDTH); dh = (int) window_get(my_canvas, WIN_HEIGHT); dws = dw/scale; dhs = dh/scale; if (cx - dws/2 <= 0) cx = dws/2; if (cy - dhs/2 <= 0) cy = dhs/2; if (cx + dws/2 >= scr_pr->pr_width) cx = scr_pr->pr_width - dws/2; if (cy + dhs/2 >= scr_pr->pr_height) cy = scr_pr->pr_height- dhs/2; GV.curx = cx; GV.cury = cy; GV.scale = scale; show_scaled(pw, 0, 0, dw, dh, scale, scr_pr, cx - dws/2, cy - dhs/2); } /*----------------------------------------------------------------------*/ get_abs_pos(win, rx, ry, cx, cy) Window win; int rx, ry, *cx, *cy; { *cx = rx; *cy = ry; while (1) { *cx += (int) window_get(win, WIN_X) + (int) window_get(win, WIN_LEFT_MARGIN); *cy += (int) window_get(win, WIN_Y) + (int) window_get(win, WIN_TOP_MARGIN); win = (Window) window_get(win, WIN_OWNER); if (win == NULL) break; } } /*----------------------------------------------------------------------*/ reset_plane_groups() { int groups[10]; pr_available_plane_groups(scr_pr, 10, groups); if (GV.depth == 8 && groups[PIXPG_8BIT_COLOR]) pr_set_plane_group(scr_pr, PIXPG_8BIT_COLOR); else if (GV.depth == 1 && groups[PIXPG_8BIT_COLOR]) pr_set_plane_group(scr_pr, PIXPG_OVERLAY); else { pr_set_plane_group(scr_pr, PIXPG_MONO); GV.depth = 1; } } /*----------------------------------------------------------------------*/ init_screen() { scr_pr = pr_open("/dev/fb"); reset_plane_groups(); } /*----------------------------------------------------------------------*/ main(argc, argv) int argc; char *argv[]; { Panel panel; Icon icon; init_screen(); init_scaletable(MAXSCALE); icon = icon_create(ICON_IMAGE, &glas_pr, 0); my_frame = window_create(NULL, FRAME, FRAME_LABEL, "lglass", FRAME_ICON, icon, FRAME_ARGS, argc, argv, 0); panel = window_create(my_frame, PANEL, 0); panel_create_item(panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image(panel, "Select", 0, 0), PANEL_EVENT_PROC, init_grab_proc, 0); panel_create_item(panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image(panel, "Redraw", 0, 0), PANEL_NOTIFY_PROC, do_repaint, 0); panel_create_item(panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image(panel, "Done", 0, 0), PANEL_NOTIFY_PROC, do_done, 0); panel_create_item(panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image(panel, "Quit", 0, 0), PANEL_NOTIFY_PROC, do_quit, 0); window_fit_width(panel); window_fit_width(my_frame); scale_item = panel_create_item(panel, PANEL_CHOICE, PANEL_LABEL_STRING, "Scale :", PANEL_CHOICE_STRINGS, SCALESTRINGS, 0, PANEL_NOTIFY_PROC, do_set_scale, 0); panel_create_item(panel, PANEL_CHOICE, PANEL_LABEL_STRING, "Update:", PANEL_CHOICE_STRINGS, UPDATEMENUSTRINGS, 0, PANEL_NOTIFY_PROC, do_set_update, 0); panel_create_item(panel, PANEL_CHOICE, PANEL_LABEL_STRING, "Color :", PANEL_CHOICE_STRINGS, COLORSTRINGS, 0, PANEL_NOTIFY_PROC, do_set_color, 0); window_fit(panel); std_cursor = cursor_copy((Cursor) window_get(panel, WIN_CURSOR)); select_cursor = cursor_create(CURSOR_IMAGE, &select_pr, CURSOR_XHOT, 2, CURSOR_YHOT, 2, 0); my_canvas = window_create(my_frame, CANVAS, CANVAS_RETAINED, FALSE, CANVAS_REPAINT_PROC, do_repaint, CANVAS_FAST_MONO, (GV.depth == 1 ? TRUE : FALSE), WIN_X, 0, WIN_BELOW, panel, WIN_HEIGHT, (int) window_get(panel, WIN_WIDTH), WIN_EVENT_PROC, do_select, 0); window_fit(my_frame); window_main_loop(my_frame); } @@@ End of lglass.c echo show.c cat >show.c <<'@@@ End of show.c' /************************************************************************* Lglass: screen viewer for the Sun Workstation running SunView Copyright (c) 1989 by Jack van Wijk 7/24/89 @ Netherlands Energy Research Foundation, ECN This program may be redistributed without fee as long as this copyright notice is intact. ---------- Netherlands Energy Research Foundation, ECN ------------------ Jack (Jarke J.) van Wijk UUCP : jack@ecn.uucp P.O. Box 1, 1755 ZG Petten(NH) ARPA : ecn!jack@nluug.nl Holland phone: +31 2246 4333 ecn!jack@uunet.uu.net *************************************************************************/ #include <suntool/sunview.h> #include <suntool/window.h> static u_char **scaletable; /*----------------------------------------------------------------------*/ init_scaletable(max_scale) int max_scale; { int i, j, k, bit, scale, srcbit; u_char *tab; scaletable = (u_char **) malloc((scale_to_nr(max_scale)+1)*sizeof(u_char *)); scale = 2; for (scale = 2, i=1; scale < 64; i++, scale *=2) /* For each scale a set */ { scaletable[i] = (u_char *) malloc(16*scale/2); tab = scaletable[i]; for (j = 0; j < 16; j++) /* For each nibble */ for (k = scale/2-1; k>=0; k--) /* For each scaled nibble */ { *tab = 0; for (bit = 7; bit >= 0; bit--) /* For each bit of dst */ { srcbit = (8*k+bit)/scale; /* inverse mapping */ if ((j >> srcbit) & 1) *tab |= 1 << bit; } tab++; } } } /*----------------------------------------------------------------------*/ static mem_scale8(mem_src, mem_dst, dh, scale) Pixrect *mem_src, *mem_dst; int dh, scale; { register u_char *lxsrc, *lxdst, *lxmax; u_char *lysrc, *lydst, *lymax; int lbsrc, lbdst; int i; /* Calculate memory locations */ lbsrc = mpr_d(mem_src)->md_linebytes; lbdst = mpr_d(mem_dst)->md_linebytes; lysrc = (u_char *) mpr_d(mem_src)->md_image; lydst = (u_char *) mpr_d(mem_dst)->md_image; lymax = lysrc + (dh/scale+1)*lbsrc; /* Scale image in memory */ for (;lysrc < lymax; lysrc += lbsrc, lydst += scale*lbdst) { lxsrc = lysrc; lxdst = lydst; lxmax = lxsrc + lbsrc; for (; lxsrc < lxmax; lxsrc++) { for (i=0; i < scale; i++) *lxdst++ = *lxsrc; } for (i=1; i < scale; i++) memcpy(lydst+i*lbdst, lydst, lbdst); } } /*----------------------------------------------------------------------*/ static mem_scale1(mem_src, mem_dst, dh, scale) Pixrect *mem_src, *mem_dst; int dh, scale; { int lbsrc, lbdst; register u_char *lxsrc, *lxdst, *lxmax; u_char *lysrc, *lydst, *lymax; register u_char *tab, *v1, *v2; register int i, nscale; tab = scaletable[scale_to_nr(scale)]; lbsrc = mpr_d(mem_src)->md_linebytes; lbdst = mpr_d(mem_dst)->md_linebytes; lysrc = (u_char *) mpr_d(mem_src)->md_image; lydst = (u_char *) mpr_d(mem_dst)->md_image; lymax = lysrc + (dh/scale+1)*lbsrc; nscale= scale / 2; for (;lysrc < lymax; lysrc += lbsrc, lydst += scale*lbdst) { lxsrc = lysrc; lxdst = lydst; lxmax = lxsrc + lbsrc; for (; lxsrc < lxmax; lxsrc++) { v1 = tab + (*lxsrc >> 4) * nscale; v2 = tab + (*lxsrc & 15) * nscale; if (nscale == 1) { *lxdst++ = *v1; *lxdst++ = *v2; } else { memcpy(lxdst, v1, nscale); lxdst += nscale; memcpy(lxdst, v2, nscale); lxdst += nscale; } } for (i=1; i < scale; i++) memcpy(lydst+i*lbdst, lydst, lbdst); } } /*----------------------------------------------------------------------*/ show_scaled(pw, dx, dy, dw, dh, scale, pr, sx, sy) Pixwin *pw; int dx, dy, dw, dh, scale; Pixrect *pr; int sx, sy; { static Pixrect *mem_src=NULL, *mem_dst=NULL; if (scale == 1) { pw_write(pw, dx, dy, dw, dh, PIX_SRC, pr, sx, sy); return; } /* Allocate memory buffers */ if (mem_src == NULL || mem_src->pr_width != dw/scale + 1 || mem_src->pr_height!= dh/scale + 1 || mem_src->pr_depth != pr->pr_depth) { if (mem_src != NULL) pr_destroy(mem_src); mem_src = mem_create(dw/scale+1, dh/scale+1, pr->pr_depth); } if (mem_dst == NULL || mem_dst->pr_width != (dw/scale + 1)*scale || mem_dst->pr_height!= (dh/scale + 1)*scale || mem_dst->pr_depth != pr->pr_depth) { if (mem_dst != NULL) pr_destroy(mem_dst); mem_dst = mem_create((dw/scale + 1)*scale, (dh/scale + 1)*scale, pr->pr_depth); } /* Read source image into memory */ pr_rop(mem_src, 0, 0, (dw/scale +1)*scale, (dh/scale +1)*scale, PIX_SRC, pr, sx, sy); /* Scale memory to memory */ if (pr->pr_depth == 8) mem_scale8(mem_src, mem_dst, dh, scale); else mem_scale1(mem_src, mem_dst, dh, scale); /* Copy memory to destination pixwin */ pw_write(pw, dx, dy, dw, dh, PIX_SRC, mem_dst, 0, 0); } @@@ End of show.c echo select.cursor cat >select.cursor <<'@@@ End of select.cursor' /* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 */ 0x1F00,0x2080,0x4040,0x8020,0x8020,0x8020,0x8020,0x8020, 0x4060,0x20D0,0x1FA8,0x0054,0x002A,0x0015,0x000A,0x0004 @@@ End of select.cursor echo lglass.icon cat >lglass.icon <<'@@@ End of lglass.icon' /* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16 */ 0x8888,0x8888,0x8FF8,0x8888,0x8888,0x8888,0xFFFF,0x8888, 0x2222,0x2223,0xF007,0xE222,0x2222,0x222F,0x8FF8,0xFA22, 0x8888,0x889C,0x7C0F,0x1C88,0x8888,0x88B9,0x8C0C,0xCE88, 0x2222,0x22E6,0x0C0C,0x33A2,0x2222,0x23CC,0x0C0C,0x0962, 0x8888,0x8990,0xC0C0,0xC4C8,0x8888,0x8B20,0xC0C0,0xC268, 0x2222,0x2640,0xC0C0,0xC132,0x2222,0x2AC0,0xC0C0,0xC0AA, 0x8888,0x8D0C,0x0C0C,0x0C58,0x8888,0x990C,0x0C0C,0x0C4C, 0x2222,0x3A0C,0x0C0C,0x0C2E,0x2222,0x3A0C,0x0C0C,0x0C2E, 0x8888,0xB4C0,0xC0C0,0xC0D6,0x8888,0xB4C0,0xC0C0,0xC0D6, 0x2222,0x34C0,0xC0C0,0xC0D6,0x2222,0x68C0,0xC0C0,0xC0CB, 0x8888,0xEC0C,0x0C0C,0x0C0B,0x8888,0xEC0C,0x0C0C,0x0C0B, 0x2222,0x6C0C,0x0C0C,0x0C0B,0x2222,0x6C0C,0x0C0C,0x0C0B, 0x8888,0xE8C0,0xC0C0,0xC0CB,0x8888,0xE8C0,0xC0C0,0xC0CB, 0x2222,0x68C0,0xC0C0,0xC0CB,0x2222,0x68C0,0xC0C0,0xC0CB, 0x8888,0xB40C,0x0C0C,0x0C16,0x8888,0xB40C,0x0C0C,0x0C16, 0x2222,0x340C,0x0C0C,0x0C16,0x2222,0x3A0C,0x0C0C,0x0C2E, 0x8888,0x9AC0,0xC0C0,0xC0EC,0x8888,0x99C0,0xC0C0,0xC0CC, 0x2222,0x2DC0,0xC0C0,0xC0DA,0x2222,0x2AC0,0xC0C0,0xC0BA, 0x8888,0x9E4C,0x0C0C,0x0D38,0x8888,0xBB2C,0x0C0C,0x0E68, 0x2222,0x669C,0x0C0C,0x0CE2,0x2222,0x198C,0x0C0C,0x09E2, 0x8889,0x1766,0xC0C0,0xF388,0x888B,0x0EE9,0xC0C0,0xCE88, 0x2226,0xE5D4,0x70C7,0x1E22,0x222D,0xB3BF,0x8FF8,0xFA22, 0x889B,0x71BB,0xF007,0xE888,0x88B6,0xE878,0xFFFF,0x8888, 0x226D,0xDE62,0x2FFA,0x2222,0x22DB,0xBA22,0x2222,0x2222, 0x89B7,0x7688,0x8888,0x8888,0x8B6E,0xED88,0x8888,0x8888, 0x26DD,0xDBA2,0x2222,0x2222,0x2DBB,0xB622,0x2222,0x2222, 0x9B77,0x6C88,0x8888,0x8888,0xB6EE,0xD888,0x8888,0x8888, 0x6DDD,0xB222,0x2222,0x2222,0x3BBB,0x6222,0x2222,0x2222, 0x9776,0xC888,0x8888,0x8888,0x8EED,0x8888,0x8888,0x8888, 0x2DDB,0x2222,0x2222,0x2222,0x23B6,0x2222,0x2222,0x2222, 0x8B6C,0x8888,0x8888,0x8888,0x88D8,0x8888,0x8888,0x8888, 0x22B2,0x2222,0x2222,0x2222,0x2262,0x2222,0x2222,0x2222 @@@ End of lglass.icon echo lglass.man cat >lglass.man <<'@@@ End of lglass.man' .TH LGLASS 1 "24 July 1989" .SH NAME lglass\- look at your screen through a looking-glass .SH SYNOPSIS .B lglass .SH DESCRIPTION .LP \fILglass\fP is SunView-based tool for examining the screen. At each moment an area around a selected spot is displayed at a user-definable scale. After start-up a window appears, divided in two sub-windows: a control-panel for setting options, and a canvas for showing the selected part of the screen. The buttons have the following meaning: .IP \fBSelect\fP 10 Enables the user to change the currently selected spot on the screen. After pressing the button, the cursor changes to a looking-glass. When the left mouse-button is pressed, a new spot is selected, and the area around it is displayed in the canvas. With the middle-button down, the spot can be dragged, and the currently selected area is modified dynamically. When the middle-button is released, the selection is made. .IP \fBRedraw\fP 10 Redraw the canvas according to the current setting. .IP \fBDone\fP 10 Close the window. A looking-glass icon appears. .IP \fBQuit\fP 10 Quit from lglass. .LP The choices below the buttons mean: .IP \fBScale\fP 10 Select the scale for enlarging the screen. .IP \fBUpdate\fP 10 Select the mode for updating the canvas: \fIoff\fP - no update; \fIslow\fP - update canvas each second; and \fIfast\fP - update canvas each 1/5th second. .IP \fBColor\fP 10 Select whether black-and-white planes, or color-planes must be shown. .LP Further the scaled image can be modified when the cursor is inside the canvas. With the \fIleft-button\fP a new spot can be selected: the canvas is redrawn, with the selected spot at the center of the canvas. With the \fImiddle-button\fP the image can be dragged. When the \fIright-button\fP is pressed, a menu appears showing \fBzoom in, zoom out\fP. After a choice is made, the canvas is redrawn at a modified scale, with the selected spot at the center of the canvas. .SH AUTHOR Jack van Wijk, ECN, PO box 1, 1755 ZG Petten (NH), Holland. .SH BUGS Please contact me about bugs and wishes. .SH NOTES The development of \fIlglass\fP is part of a research project of the \fINetherlands Energy Research Foundation (ECN), Petten (NH), Holland\fP. @@@ End of lglass.man exit 0