[comp.sources.sun] v01i091: ALV - An Image Processing Toolkit, Part07/10

mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (12/12/89)

Submitted-by: everson@compsci.bristol.ac.uk
Posting-number: Volume 1, Issue 91
Archive-name: alv/part07



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 7 (of 10)."
# Contents:  src/cst.c src/dsp.c src/glass.c
# Wrapped by everson@kukini on Tue Oct 17 07:45:13 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/cst.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/cst.c'\"
else
echo shar: Extracting \"'src/cst.c'\" \(8039 characters\)
sed "s/^X//" >'src/cst.c' <<'END_OF_FILE'
X/***************************************************************************/
X/* This program is a heavily-modified version of Phil Everson's winlev8    */
X/* from the ALV v2.1 suite of public domain image processing programs for  */
X/* Sun workstations.  It allows interactive thresholding and contrast      */
X/* -stretching of greyscale images by manipulating the lookup tables (LUTs)*/
X/* Only greyscales from 1 to 254 are permitted. The LUTs can be saved to   */
X/* a file for incorporation into a rasterfile header for the image.        */
X/*                                                                         */
X/*                           cst.c                                         */
X/*                                                                         */
X/* Bryan Dawson, Keele University Geography Dept (JANET: ged08@keele.seq1) */
X/*                                                      27/3/89            */
X/***************************************************************************/
X
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X#include <suntool/panel.h>
X#include <stdio.h>
X#include "defs.h"
X
X#define CSTFONT "/usr/lib/fonts/fixedwidthfonts/cour.r.16"
X#define XSIZE 256
X#define YSIZE 256
X#define MaxY 254
X#define MinY 1
X
char           *progname;
X
static short    csticon[] =
X{
X#include "../images/icons/cst.icon"
X};
X
DEFINE_ICON_FROM_IMAGE(icon, csticon);
X
static void save_proc(),getcoords(), repaint_canvas(), invert0_proc(), quit_proc(), reset_proc();
int     invert0 = 0,fcount = 0;
int     yval = 255, xval = 127, lolim = MinY, hilim = MaxY;
char           *progname;
XFILE * lutfile;
XFrame       frame;
Canvas      canvas;
Panel       panel, inv_panel;
Pixfont        *font;
Pixwin         *pw, *pw2;
char        cmsname[CMS_NAMESIZE];
u_char      red[256], ref[256];/* all LUTs the same, so red used 3 times */
X
X#ifdef STANDALONE
main(argc, argv, envp)
X#else
cst_main(argc, argv, envp)
X#endif
X    int      argc;
X    char           **argv;
X    char           **envp;
X
X{
X    int      i, j, x, y;
X    u_char  *pi;
X    char        *makethelabel();
X
X    progname = strsave(argv[0]);
X    parse_profile(&argc, argv, envp);/* link with support.c */
X
X    while ((gc = getopt(argc, argv, " ")) != EOF)
X        switch (gc) {
X        case '?':
X            errflag++;
X            break;
X        }
X
X    if (errflag)
X        error((char *) 0, "Usage: %s:\n", progname);
X
X    if ((font = pf_open(CSTFONT)) == NULL) {
X        fprintf(stderr, "%s : Cannot open %s\n", argv[0], CSTFONT);
X        exit(1);
X    }
X
X /* Initialise default grey scale ramp */
X    for (i = 0; i < 256; i++) red[i] = ref[i] = i;
X    red[0] = ref[0] = 255;
X    red[255] = ref[255] = 0;
X
X    /* create frame and canvas */
X    frame = window_create(NULL, FRAME,
X                 FRAME_LABEL, makethelabel(),
X                 WIN_HEIGHT, YSIZE + 56,
X                 WIN_WIDTH, XSIZE + 10,
X                 FRAME_ICON, &icon,
X                 FRAME_ARGS, argc, argv,
X                 0);
X
X    panel = window_create(frame, PANEL, 0);
X
X    inv_panel = panel_create_item(panel, PANEL_CYCLE,
X                   PANEL_CHOICE_STRINGS, "Normal", "Invert", 0,
X                      PANEL_NOTIFY_PROC, invert0_proc,
X                      0);
X    panel_create_item(panel, PANEL_BUTTON,
X        PANEL_LABEL_IMAGE, panel_button_image(panel, "Save", 0, 0),
X            PANEL_NOTIFY_PROC, save_proc,
X            0);
X    panel_create_item(panel, PANEL_BUTTON,
X        PANEL_LABEL_IMAGE, panel_button_image(panel, "Reset", 0, 0),
X              PANEL_NOTIFY_PROC, reset_proc,
X              0);
X    panel_create_item(panel, PANEL_BUTTON,
X         PANEL_LABEL_IMAGE, panel_button_image(panel, "Quit", 0, 0),
X              PANEL_NOTIFY_PROC, quit_proc,
X              0);
X
X    window_fit(panel);
X    window_set(panel, WIN_WIDTH, XSIZE, 0);
X
X    canvas = window_create(frame, CANVAS,
X                  WIN_BELOW, panel,
X                  WIN_X, 0,
X                  WIN_EVENT_PROC, getcoords,
X                  0);
X
X    /* get the canvas pixwin to draw into */
X    pw = canvas_pixwin(canvas);
X
X    /* Set colour map segment */
X    pw_setcmsname(pw, "grays");
X    pw_putcolormap(pw, 0, 256, red, red, red);
X
X    window_set(canvas, WIN_CONSUME_PICK_EVENTS, LOC_DRAG, 0, 0);
X
X/* N.B. The Y origin is top left of window, not bottom left */
X    pw_vector(pw, lolim, MaxY, hilim, MinY, PIX_SRC, 255);
X    window_main_loop(frame);
X}
X
static void 
repaint_canvas()
X{
pw_writebackground(pw,0,0,256,256,PIX_SRC);
X}
X
static void
invert0_proc(item, value, event)
X    Panel_item   item;
X    int      value;
X    Event       *event;
X{
register int p;
X    invert0 = value;
for (p=0;p<256;p++) red[p] = 255 - red[p];
X    setcolormap();
X}
X
static void
getcoords(canvas, event, arg)
X    Canvas   canvas;
X    Event       *event;
X    caddr_t  arg;
X{
X    register int q;
X    char *makethelabel();
X
X    switch(event_id(event))
X        {
X    case LOC_DRAG :
X    case MS_MIDDLE:
X       repaint_canvas();         /* clear window */
X       yval = 255 - event_y(event); /* where's the cursor ? */
X       xval = event_x(event);
X       if (xval < lolim) xval = lolim; /* trap over/under ranges */
X       if (xval > hilim) xval = hilim;
X       pw_vector(pw,lolim,255,xval,255 - yval,PIX_SRC,255);
X       pw_vector(pw,xval,255 - yval,hilim,0,PIX_SRC,255);
X       stretchlut(lolim,MinY,xval,yval,0);
X       stretchlut(xval,yval,hilim,MaxY,yval);
X       if (invert0) for (q=1;q<255;q++) red[q] = 255 - red[q];
X       pw_putcolormap(pw, 0, 256, red, red, red);
X       break;
X     case MS_LEFT :
X       repaint_canvas();
X       lolim = event_x(event);
X       if (lolim >= hilim) lolim = hilim - 1;
X       pw_vector(pw,lolim,255,hilim,0,PIX_SRC,255);
X       stretchlut(lolim,MinY,hilim,MaxY,0);
X       if (invert0) for (q=1;q<255;q++) red[q] = 255 - red[q];
X       pw_putcolormap(pw, 0, 256, red, red, red);
X       window_set(frame,FRAME_LABEL,makethelabel(),0);
X       break;       
X     case MS_RIGHT :
X       repaint_canvas();
X       hilim = event_x(event);
X       if (hilim <= lolim) hilim = lolim + 1;
X       pw_vector(pw,lolim,255,hilim,0,PIX_SRC,255);
X       stretchlut(lolim,MinY,hilim,MaxY,0);
X       if (invert0) for (q=1;q<255;q++) red[q] = 255 - red[q];
X       pw_putcolormap(pw, 0, 256, red, red, red);
X       window_set(frame,FRAME_LABEL,makethelabel(),0);
X       break;
X        } /* end of switch */
X}
X
stretchlut(lox,loy,hix,hiy,base)
int lox,loy,hix,hiy,base;
X{
int i,rangex,rangey,temp;
double a;
X
X    rangex = hix - lox + 1;
X    rangey = hiy - loy + 1;
X    a = (double)rangey / (double)rangex; /* scaling factor */
for (i=MinY;i<lolim;i++) red[i] = 0;
for (i=hilim;i<MaxY;i++); red[i] = 255;
for (i=lox;i<hix;i++)
X    {
X    temp = (int)((i - lox + 1) * a); /* offset & gain compensation */
X    temp += base;           /* for top of two-part stretch */
X    if (temp < 1) temp = 1; /* avoid exteme values - used for text */
X    if (temp > 254) temp = 254;
X    red[i] = (unsigned char)temp;
X    }
X}
X
setcolormap()
X{
int i;
X
X/* Initialise variables used to set colour map */
red[0] = 255;
red[255] = 0;
pw_putcolormap(pw, 0, 256, red, red, red);
X}
X
char *
makethelabel()
X{
X    static char  buf[BUFSIZ];
X    char        *sprintf();
X    return sprintf(buf, "Lolim = %3d  Hilim = %3d", lolim, hilim);
X}
X
static void
quit_proc()
X{
X    window_set(frame, FRAME_NO_CONFIRM, TRUE, 0);
X    window_destroy(frame);
X}
X
static void
reset_proc()
X{
register int i;
X
X    repaint_canvas(); /* clear window & redraw line */
X    pw_vector(pw,lolim,MaxY,hilim,MinY,PIX_SRC,255);
X
X    invert0 = 0; /* reset normal/invert0 toggle */
X    panel_set_value(inv_panel, invert0);
X
X    for (i = 0; i < 256; i++) red[i] = i; /* plain ramp */
X    setcolormap();
X
X    lolim = MinY; hilim = MaxY; /* default labels */
X    window_set(frame, FRAME_LABEL, makethelabel(), 0);
X}
X
static void
save_proc()
X{
int id;
char fname[10];
X
sprintf(fname,"clut.%03d",++fcount);
lutfile = fopen(fname,"w");
id = fwrite(red,1,256,lutfile);
id = fwrite(red,1,256,lutfile);
id = fwrite(red,1,256,lutfile);
id = fclose(lutfile);
X}
END_OF_FILE
if test 8039 -ne `wc -c <'src/cst.c'`; then
    echo shar: \"'src/cst.c'\" unpacked with wrong size!
fi
# end of 'src/cst.c'
fi
if test -f 'src/dsp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/dsp.c'\"
else
echo shar: Extracting \"'src/dsp.c'\" \(11523 characters\)
sed "s/^X//" >'src/dsp.c' <<'END_OF_FILE'
X#include "defs.h"
X#include <fcntl.h>
X
X#define DEFAULT_WIN_XSIZE	850
X#define DEFAULT_WIN_YSIZE	1000
X#define MIN_WIN_XSIZE		200
X#define MIN_WIN_YSIZE		200
X
XFrame   frame;
Canvas  canvas;
Cursor  cursor;
Icon    icon;
Panel   panel;
Panel_item window_slider, level_slider;
Pixwin *pw, *fpw;
Pixrect *pr, *dpr, *icon_pr, *backing_pixrect, *mem_create();
X
static short dspicon[] =
X{
X#include "../images/icons/dsp.icon"
X};
DEFINE_ICON_FROM_IMAGE(bwicon, dspicon);
X
Menu    canvas_menu;
static void
getcoords(), window_proc(), level_proc(), canvas_proc(),
repaint_canvas(), resize_canvas();
X
char    cmsname[BUFSIZ];
u_char  red[256], green[256], blue[256];
char   *progname;
char   *filename;
char   *eight_to_one;
char    buf1[BUFSIZ];
int     window, level;
int     old_level, old_window;
int     max_level, min_level;
int     lower, upper;
int     table[10000];
int     winxsize, winysize;
int     size, wl, colour;
colormap_t colormap;
Panel_item next_butt, prev_butt;
static void dummy_proc(), canvas_event_proc();
X
X#ifdef STANDALONE
main(argc, argv, envp)
X#else
dsp_main(argc, argv, envp)
X#endif
X	int     argc;
X	char  **argv;
X	char  **envp;
X{
X	int     i;
X	int     scroll_thickness;
X	float   calc_mean();
X	Pixrect *call_dither();
X
X	eight_to_one = NULL;
X	progname = strsave(argv[0]);
X	parse_profile(&argc, argv, envp);
X
X	filename = strsave("stdin");
X	while ((gc = getopt(argc, argv, "W:bc8:")) != EOF)
X		switch (gc) {
X		case '8':
X			eight_to_one = strsave(optarg);
X			break;
X		case '?':
X			errflag++;
X			break;
X		}
X
X	if (errflag)
X		error((char *) 0, "Usage: %s: [-8 program] [infile]\n", progname);
X
X	for (stream = 0; optind < argc; stream++, optind++)
X		if (stream == 0 && strcmp(argv[optind], "-") != 0) {
X			filename = strsave(argv[optind]);
X			if (freopen(argv[optind], mode[stream], f[stream]) == NULL)
X				error("%s %s", PR_IO_ERR_INFILE, argv[optind]);
X		}
X	if (eight_to_one == NULL)
X		eight_to_one = strsave(FILTER8TO1);
X
X	if ((pr = pr_load(stdin, &colormap)) == NULL)
X		error(PR_IO_ERR_RASREAD);
X
X	frame = window_create(NULL, FRAME, FRAME_NO_CONFIRM, TRUE, 0);
X	canvas = window_create(frame, CANVAS, 0);
X	pw = canvas_pixwin(canvas);
X	colour = iscolour(pw);
X	window_destroy(frame);
X
X	if (!colour) {
X		if (pr->pr_depth == 8)
X			pr = call_dither(pr);
X		if (pr->pr_depth > 8)
X		    error("Input depth not supported on this workstation");
X	}
X
X	setup_windowsizes();
X
X	scroll_thickness = defaults_get_integer("/Scrollbar/Thickness", 14, 0);
X	frame = window_create(NULL, FRAME,
X			      FRAME_LABEL, filename,
X			      WIN_HEIGHT, winysize + scroll_thickness + 7,
X			      WIN_WIDTH, winxsize + scroll_thickness + 10,
X			      FRAME_ARGS, argc, argv,
X			      0);
X
X    	if (colour) {
X		setup_colourmap();
X		if (colormap.length != 0) {
X		    if (!mono_override)
X		    	allow_mono(pr);
X		    }
X		}
X
X	max_level = calc_max(pr)+1;
X	if (pr->pr_depth > 8 && colormap.length == 0) {
X		window = MAXLEVEL(8);
X		level = (int) calc_mean(pr);
X		old_window = max_level;
X		old_level = max_level / 2;
X		setup_scrollbars();
X	}
X	cursor = cursor_create(
X			       CURSOR_OP, PIX_SRC ^ PIX_DST,
X			       CURSOR_CROSSHAIR_LENGTH, 20,
X			       CURSOR_SHOW_CROSSHAIRS, TRUE,
X			       0);
X
X	canvas = window_create(frame, CANVAS,
X			       WIN_CURSOR, cursor,
X			       CANVAS_HEIGHT, pr->pr_size.y,
X			       CANVAS_WIDTH, pr->pr_size.x,
X			       CANVAS_AUTO_SHRINK, FALSE,
X			       WIN_EVENT_PROC, canvas_event_proc,
X			       WIN_CONSUME_PICK_EVENT, LOC_MOVE,
X			       0);
X
X	if (pr->pr_depth > 8)
X		window_set(canvas, WIN_BELOW, panel, WIN_X, 0, 0);
X
X	pw = canvas_pixwin(canvas);
X
X	window_set(canvas,
X		   WIN_VERTICAL_SCROLLBAR, scrollbar_create(0),
X		   WIN_HORIZONTAL_SCROLLBAR, scrollbar_create(0),
X		   0);
X
X	if (pr->pr_depth <= 8)
X		dpr = pr;
X	else {
X		if ((dpr = mem_create(pr->pr_size.x, pr->pr_size.y, 8)) == NULL)
X			error("mem_create returned NULL");
X		min_level = 0;
X		setup_table();
X		convert_to_8bits(pr, dpr);
X	}
X
X	if (pr->pr_depth == 1 || !colour)
X		window_set(frame, FRAME_ICON, &bwicon, 0);
X	else {
X		icon_pr = mem_create(64, 64, 8);
X		paint_icon();
X	}
X
X	pw_rop(pw, 0, 0, dpr->pr_size.x, pr->pr_size.y, PIX_SRC, dpr, 0, 0);
X	window_main_loop(frame);
X}
paint_icon()
X{
X	subsample(dpr, icon_pr);
X
X	icon = icon_create(ICON_IMAGE, icon_pr, 0);
X	window_set(frame, FRAME_ICON, icon, 0);
X}
subsample(in, out)
X	Pixrect *in, *out;
X{
X	int     cvx, cvy, lcx, lcy, hcx, hcy;
X	register int i, j, i1, j1;
X	int     total;
X
X	cvx = (100 * in->pr_size.x) / out->pr_size.x;
X	cvy = (100 * in->pr_size.y) / out->pr_size.y;
X
X	for (j = 0; j < out->pr_size.y; j++)
X		for (i = 0; i < out->pr_size.x; i++) {
X			hcx = i * cvx / 100;
X			hcy = j * cvy / 100;
X			lcx = (i - 1) * cvx / 100 + 1;
X			lcy = (j - 1) * cvy / 100 + 1;
X			lcx = (lcx < 0) ? 0 : (lcx > hcx) ? hcx : lcx;
X			lcy = (lcy < 0) ? 0 : (lcy > hcy) ? hcy : lcy;
X
X			total = 0;
X			for (j1 = lcy; j1 <= hcy; j1++)
X				for (i1 = lcx; i1 <= hcx; i1++)
X					total += pr_get(in, i1, j1);
X			pr_put(out, i, j, (total / ((hcx + 1 - lcx) * (hcy + 1 - lcy))));
X		}
X}
setup_scrollbars()
X{
X	setup_font();
X
X	panel = window_create(frame, PANEL,
X			      WIN_WIDTH, WIN_EXTEND_TO_EDGE,
X			      0);
X
X	window_slider = panel_create_item(panel, PANEL_SLIDER,
X					  PANEL_ITEM_X, ATTR_COL(0),
X					  PANEL_ITEM_Y, ATTR_ROW(0),
X					  PANEL_LABEL_FONT, font,
X					  PANEL_LABEL_STRING, "Window:",
X					  PANEL_VALUE, window,
X					  PANEL_MIN_VALUE, 0,
X					  PANEL_MAX_VALUE, max_level,
X					  PANEL_NOTIFY_PROC, window_proc,
X					  0);
X
X	level_slider = panel_create_item(panel, PANEL_SLIDER,
X					 PANEL_ITEM_X, ATTR_COL(0),
X					 PANEL_ITEM_Y, ATTR_ROW(1),
X					 PANEL_LABEL_FONT, font,
X					 PANEL_LABEL_STRING, "Level :",
X					 PANEL_VALUE, level,
X					 PANEL_MIN_VALUE, 0,
X					 PANEL_MAX_VALUE, max_level,
X					 PANEL_NOTIFY_PROC, level_proc,
X					 0);
X
X	window_fit_height(panel);
X}
X
static void
window_proc(item, value, event)
X	Panel_item item;
X	int     value;
X	Event  *event;
X{
X	int     ol;
X
X	ol = level;
X	window = value;
X
X	if (level + window / 2 >= max_level)
X		level = max_level - window / 2;
X	if (level - window / 2 < min_level)
X		level = window / 2;
X	if (ol != level)
X		panel_set(level_slider, PANEL_VALUE, level, 0);
X	setup_table();
X	convert_to_8bits(pr, dpr);
X	pw_rop(pw, 0, 0, dpr->pr_size.x, pr->pr_size.y, PIX_SRC, dpr, 0, 0);
X	paint_icon();
X}
X
static void
level_proc(item, value, event)
X	Panel_item item;
X	int     value;
X	Event  *event;
X{
X	level = value;
X
X	if (level + window / 2 >= max_level)
X		level = max_level - window / 2;
X	if (level - window / 2 < min_level)
X		level = window / 2;
X	if (level != value)
X		panel_set(level_slider, PANEL_VALUE, level, 0);
X	setup_table();
X	convert_to_8bits(pr, dpr);
X	pw_rop(pw, 0, 0, dpr->pr_size.x, pr->pr_size.y, PIX_SRC, dpr, 0, 0);
X	paint_icon();
X}
X/* initialise lookup table for current window & level */
setup_table()
X{
X	register int i;
X	register int *t;
X	register int new_lower, new_upper;
X	int     old_lower, old_upper;
X	double  m, cumulative_greylevel;
X
X	if (window != 0)
X		m = (253.) / (float) (window);	/* 253 = No. greylevels
X						 * - 1 */
X
X	cumulative_greylevel = 1.;
X	new_lower = level - window / 2;
X	new_upper = level + window / 2;
X	old_lower = old_level - old_window / 2;
X	old_upper = old_level + old_window / 2;
X
X	lower = MIN(old_lower, new_lower);
X	upper = MAX(old_upper, new_upper);
X
X	lower = 0;
X	upper = max_level;
X	t = &table[lower];
X	for (i = lower; i < upper; i++)
X		if (i <= new_lower)
X			*t++ = 1;
X		else if (i >= new_upper)
X			*t++ = 254;
X		else {
X			*t++ = cumulative_greylevel;
X			cumulative_greylevel += m;
X		}
X	old_level = level;
X	old_window = window;
X}
convert_to_8bits(in, out)
X	Pixrect *in, *out;
X{
X	short  *ptr16;
X	int    *ptr32;
X	char   *ptr8;
X	register int i;
X	int     n;
X	int     mode = TRUE;
X
X#define ALL_PIXELS	TRUE
X
X	ptr8 = (char *) mpr_d(out)->md_image;
X	n = in->pr_size.x * in->pr_size.x;
X
X	switch (in->pr_depth) {
X	case 16:
X		ptr16 = (short *) mpr_d(in)->md_image;
X		for (i = 0; i < n; i++) {
X			if ((mode == ALL_PIXELS) || ((*ptr16 >= lower) && (*ptr16 <= upper)))
X				*ptr8 = *(table + (*ptr16));
X			ptr8++;
X			ptr16++;
X		}
X		break;
X	case 32:
X		ptr32 = (int *) mpr_d(in)->md_image;
X		for (i = 0; i < n; i++) {
X			if ((mode == ALL_PIXELS) || ((*ptr32 >= lower) && (*ptr32 <= upper)))
X				*ptr8 = *(table + (*ptr32));
X			ptr8++;
X			ptr16++;
X		}
X		break;
X	}
X}
setup_windowsizes()
X{
X	if (pr->pr_size.x > DEFAULT_WIN_XSIZE)
X		winxsize = DEFAULT_WIN_XSIZE;
X	else
X		winxsize = MAX(pr->pr_size.x, MIN_WIN_XSIZE)+3;
X
X	if (pr->pr_size.y > DEFAULT_WIN_YSIZE)
X		winysize = DEFAULT_WIN_YSIZE;
X	else
X		winysize = MAX(pr->pr_size.y, MIN_WIN_YSIZE)+17;
X}
setup_colourmap()
X{
X	register int i;
X
X	for (i = 0; i < 256; i++) {
X		red[i] = green[i] = blue[i] = -1;
X	}
X	fpw = (Pixwin *) window_get(frame, WIN_PIXWIN);
X
X	if (colormap.type == RMT_NONE || colormap.length == 0) {
X		sprintf(cmsname, "greyscale%d", pr->pr_depth);
X
X		pw_setcmsname(fpw, cmsname);
X
X		for (i = 1; i < 255; i++) {
X			red[i] = i;
X			green[i] = i;
X			blue[i] = i;
X		}
X		if (mono_override) {
X			red[255] = blue[255] = green[255] = 255;
X			red[0] = blue[0] = green[0] = 0;
X		}
X		pw_putcolormap(fpw, 0, 256, red, green, blue);
X	} else {
X		pw_setcmsname(fpw, "non_greyscale");
X		pw_putcolormap(fpw, 0, colormap.length, colormap.map[0], colormap.map[1], colormap.map[2]);
X	}
X	window_set(frame, FRAME_INHERIT_COLORS, TRUE, 0);
X}
X
float
calc_mean(pr)
X	Pixrect *pr;
X{
X	register int i, j;
X	int     sum;
X
X	sum = 0;
X	for (j = 0; j < pr->pr_size.y; j++)
X		for (i = 0; i < pr->pr_size.x; i++)
X			sum += pr_get(pr, i, j);
X
X	return (sum / (pr->pr_size.x * pr->pr_size.y));
X}
X
static void
canvas_event_proc(canvas, event, arg)
X	Canvas  canvas;
X	Event  *event;
X	caddr_t arg;
X{
X	char    buf[BUFSIZ];
X
X	if (event_id(event) == LOC_MOVE || event_is_button(event)) {
X		sprintf(buf, "%s - %d, %d = %d", filename, event_x(event), event_y(event), pr_get(pr, event_x(event), event_y(event)));
X		window_set(frame, FRAME_LABEL, buf, 0);
X	}
X}
iscolour(pw)
X	Pixwin *pw;
X{
X
X	return ((pw->pw_pixrect->pr_depth > 1) ? TRUE : FALSE);
X}
X
Pixrect *
call_dither(in)
X	Pixrect *in;
X{
X	Pixrect *out, *pr_load();
X	FILE   *fp_tochild;
X	FILE   *fp_fromchild;
X	int     childpid;
X	int     pfdout[2], pfdin[2];
X	int     c, numfds;
X
X	if (pipe(pfdout) == -1 || pipe(pfdin) == -1) {
X		perror(progname);
X		exit(1);
X	}
X	switch (childpid = fork()) {
X	case -1:
X		perror(progname);
X		exit(1);
X	case 0:
X		if (close(0) == -1)
X			perror(progname);
X		if (dup(pfdout[0]) != 0)
X			perror(progname);
X		if (close(1) == -1)
X			perror(progname);
X		if (dup(pfdin[1]) != 1)
X			perror(progname);
X		if (close(pfdout[0]) == -1 || close(pfdout[1]) == -1 || close(pfdin[0]) == -1 || close(pfdin[1]) == -1)
X			perror(progname);
X		execlp(eight_to_one, eight_to_one, 0);
X		perror(eight_to_one);
X		exit(1);
X	default:
X		if (close(pfdout[0]) == -1 || close(pfdin[1]) == -1)
X			perror(progname);
X
X		if ((fp_tochild = fdopen(pfdout[1], "w")) == NULL)
X			error("Can't get file descriptor to write to child process");
X		if (pr_dump(in, fp_tochild, NULL, RT_STANDARD, 0) == PIX_ERR)
X			error("pr_dump returned PIX_ERR");
X		fclose(fp_tochild);
X
X		if ((fp_fromchild = fdopen(pfdin[0], "r")) == NULL)
X			error("Can't get file descriptor to read from child process");
X		if ((out = pr_load(fp_fromchild, NULL)) == NULL)
X			error("pr_load returned NULL");
X		fclose(fp_tochild);
X	}
X	return out;
X}
X
allow_mono(pr)
Pixrect *pr;
X{
X	register int i, j, pix;
X
X	for(i=0;i<pr->pr_size.x;i++)
X		for(j=0;j<pr->pr_size.y;j++)
X			if ((pix = pr_get(pr, i, j)) == 255 || pix == 254)
X				pr_put(pr, i, j, 253);
X			else if (pix == 0)
X				pr_put(pr, i, j, 1);
X}
END_OF_FILE
if test 11523 -ne `wc -c <'src/dsp.c'`; then
    echo shar: \"'src/dsp.c'\" unpacked with wrong size!
fi
# end of 'src/dsp.c'
fi
if test -f 'src/glass.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/glass.c'\"
else
echo shar: Extracting \"'src/glass.c'\" \(16203 characters\)
sed "s/^X//" >'src/glass.c' <<'END_OF_FILE'
X/*
X *  Magnifying glass		(for Sun-3 workstations)
X *
X *  Copyright 1986, 1987 by Scott Schwartz
X *  This program may be copied with the provision that this copyright 
X *  message remains, and that further distribution of this code and it's 
X *  derivatives is not subject to additional restrictions.
X * 
X *  Lots of changes, but no Copyright, by Mark Weiser.
X * 
X *  compile with -lsuntool -lsunwindow -lpixrect
X *
X *  vi: set ts=8
X *
X *  revision history:
X *  10 Nov 86	initial coding		 		Scott Schwartz 
X *
X *  version 1.0		25 Nov 86
X *	modified to draw big pixels with raster-ops		ses
X *
X *  version 1.1		27 Jan 87
X *	does magnification in memory, 				ses
X *	to avoid screen access
X *
X *  version 1.2		27 Jan 87
X *	flood destination with white, 				ses/af
X *      then draw only black spots
X *
X *  version 2.0		15 Apr 87				mark weiser
X *	vastly faster magnification algorithm using only 2k blits
X *	instead of k**2 (where k is the height or width of the final).
X *	Also added a panel for friendliness, and stopped using *all* the cpu!
X *
X *  version 2.1		17 Apr 87				mark weiser
X *	added locking.
X *
X *  version 2.2		20 Apr 87				mark weiser
X *	added changes for color suns (not tested here).
X *
X *  version 2.3		6 June 87				Ed Falk
X *	general clean-up, made to work with color suns.
X *	minor performance improvements.  Locking around the
X *	initial screen read in order to get garbage out of
X *	image.
X */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/ioctl.h>
X#include <suntool/sunview.h>
X#include <suntool/canvas.h>
X#include <suntool/panel.h>
X#include <suntool/textsw.h>
X#include <pixrect/pixrect_hs.h>
X
X/* I HATE these macros	-mdw */
X#undef min
X#undef max
X
X
X/* useful macros */
X#define ERROR(msg)  { fprintf(stderr, "%s: %s\n", argv[0], msg); exit(1); }
X
X/* forward declarations */
extern	char *getenv(), *sprintf();
extern	Notify_error	notify_dispatch();
static	Notify_value	notice_destroy_event();
static	Notify_value	update_value_proc();
static	Notify_value	update_mag_proc();
static	void	pw_mag();
static	void	view();
static	void	update();
static	void	glass_time_proc();
static	void	lock_proc(), unlock_proc();
static	void	repaint_proc(), resize_proc() ;
X
X/* constants */
static char frame_label[] = "Magnifying Glass 2.3";
static short icon_image[] = {
X#include "../images/icons/glass.icon"
X};
DEFINE_ICON_FROM_IMAGE(icon, icon_image);
X#define NILPR ((struct pixrect *)0)
X#define MAX_MAG 32
X
X/* global vars */
static struct pixrect	*tmpsrc; /* working space, to avoid screen access */ 
static struct pixrect	*tmpdst;
static int done = 0;
struct pixrect *srcpr; /* the source pixrect, i.e. the whole screen */
int rootfd;  /* file descriptor for root window, for cursor location */
X
X/* things to draw on */
Panel panel;
XFrame frame;	/* the actual window frame */
Canvas canvas;	/* our particular canvas, filling the frame */
X
int mag = 1;			/* magnification in output window */
int delay = 1000;
int locked = 0;
int locked_x, locked_y;
Panel_item time_left_item;
X
X/* 
X *  main routine
X */
main(argc,argv)
int argc;
char **argv;
X{
X	char	*parent;	/* name of the parent window, usually win0 */
X	char	*magstr = "x99999";	/* allocate space for actual string */
X	int	retcode;
X	Pixwin	*canvas_pw ;
X	int	w, h ;
X
X	/* create output window */
X	frame = window_create(NULL, FRAME, 
X		FRAME_LABEL, frame_label,
X		FRAME_ICON, &icon,
X		FRAME_ARGC_PTR_ARGV, &argc, argv,
X		/* WIN_ERROR_MSG, "Can't create Frame", */
X		0);
X
X	panel = window_create(frame, PANEL, 0);
X	(void) panel_create_item(panel, PANEL_SLIDER,
X		PANEL_LABEL_STRING, "Mag:",
X		PANEL_VALUE, mag,
X		PANEL_MIN_VALUE, 1,
X		PANEL_MAX_VALUE, MAX_MAG,
X		PANEL_SHOW_RANGE, FALSE,
X		PANEL_SHOW_VALUE, TRUE,
X		PANEL_SLIDER_WIDTH, 100,
X		PANEL_NOTIFY_PROC, update_mag_proc,
X		PANEL_CLIENT_DATA, &mag,
X		0);
X	(void) panel_create_item(panel, PANEL_SLIDER,
X		PANEL_LABEL_STRING, "Delay:",
X		PANEL_VALUE, 10000,
X		PANEL_MIN_VALUE, 1000,
X		PANEL_MAX_VALUE, 999999,
X		PANEL_SHOW_RANGE, FALSE,
X		PANEL_SHOW_VALUE, FALSE,
X		PANEL_SLIDER_WIDTH, 100,
X		PANEL_NOTIFY_PROC, update_value_proc,
X		PANEL_CLIENT_DATA, &delay,
X		PANEL_ITEM_X, ATTR_COL(0),
X		PANEL_ITEM_Y, ATTR_ROW(1),
X		0);
X
X	(void) panel_create_item(panel, PANEL_BUTTON,
X		PANEL_LABEL_IMAGE, panel_button_image(panel, "Lock", 6, 0),
X		PANEL_NOTIFY_PROC, lock_proc,
X		PANEL_ITEM_X, ATTR_COL(0),
X		PANEL_ITEM_Y, ATTR_ROW(2),
X		0);
X
X	(void) panel_create_item(panel, PANEL_BUTTON,
X		PANEL_LABEL_IMAGE, panel_button_image(panel, "Unlock", 6, 0),
X		PANEL_NOTIFY_PROC, unlock_proc,
X		0);
X
X	time_left_item = panel_create_item(panel, PANEL_SLIDER,
X		PANEL_LABEL_STRING, "Time Left:",
X		PANEL_VALUE, 10,
X		PANEL_MIN_VALUE, 0,
X		PANEL_MAX_VALUE, 10,
X		PANEL_SHOW_RANGE, FALSE,
X		PANEL_SHOW_VALUE, FALSE,
X		PANEL_SLIDER_WIDTH, 100,
X		PANEL_ITEM_X, ATTR_COL(0),
X		PANEL_ITEM_Y, ATTR_ROW(2),
X		PANEL_SHOW_ITEM, FALSE,
X		0);
X	window_fit_height(panel);
X
X	/* gather data on output pixwin */
X	canvas = window_create(frame, CANVAS,
X		WIN_HEIGHT, 200,
X		WIN_WIDTH, 200,
X		CANVAS_RESIZE_PROC, resize_proc,
X		CANVAS_REPAINT_PROC, repaint_proc,
X		CANVAS_RETAINED, FALSE,
X		WIN_IGNORE_PICK_EVENTS, MS_RIGHT,
X			MS_MIDDLE, MS_LEFT, 0,
X		0);
X
X	window_fit(frame);
X
X	canvas_pw = canvas_pixwin(canvas);
X
X	/* open rootwindow */
X	parent = getenv("WINDOW_PARENT");
X	if (parent==NULL) 
X		ERROR("can't get WINDOW_PARENT from environment.")
X	rootfd = open(parent, O_RDONLY, 0);
X	if (rootfd<0)
X		perror(argv[0]); 
X
X	/* open frame buffer */
X	srcpr = canvas_pw->pw_pixrect ;
X
X	/* set color table from frame buffer's color table */
X
X	{
X	  unsigned char	red[256], green[256], blue[256] ;
X	  pr_getcolormap(srcpr, 0, 256, red, green, blue) ;
X	  pw_setcmsname(canvas_pw, "glass") ;
X	  pw_putcolormap(canvas_pw, 0, 256, red, green, blue) ;
X	}
X
X	/* handle arguments */		
X	if (argc > 1) {
X		retcode = sscanf(argv[1], "%d", &mag);
X		if (retcode <= 0) 
X			ERROR("\
problem evaluating arguments\n\
Usage: glass magnification [suntools-options]");
X		mag = (mag > MAX_MAG) ? MAX_MAG : mag;
X	}
X
X	/* allocate static pixrects */
X	w = (int) window_get(canvas, WIN_WIDTH) ;
X	h = (int) window_get(canvas, WIN_HEIGHT) ;
X	tmpdst = mem_create(w, h, srcpr->pr_depth);
X
X	/* set up an interposed event handler so we know when to quit */
X	(void)notify_interpose_destroy_func(frame, notice_destroy_event);
X	
X	/* start us in a second */
X	do_with_delay(glass_time_proc, 1, 0);
X
X	/* copy input to output forever */
X	window_main_loop(frame);
X	exit(0);
X}
X
X
X
static	void
resize_proc(canvas, width, height)
X	Canvas	canvas ;
X	int	width, height ;
X{
X	int	w,h ;
X
X	/* destroy and re-allocate temporary pixrects */
X
X	pr_destroy(tmpdst) ;
X
X	w = width ;
X	h = height ;
X	tmpdst = mem_create(w, h, srcpr->pr_depth);
X}
X
X
X
X
static	void
repaint_proc(canvas, pw, repaint_area)
X	Canvas		canvas ;
X	Pixwin		*pw ;
X	Rectlist	*repaint_area ;
X{
X	view(rootfd, srcpr, canvas, mag);
X}
X
X
X
X
X/*
X * Thing to do at intervals.
X */
static	void
glass_time_proc()
X{
X	if (done) return;
X	if (window_get(frame, FRAME_CLOSED)) {
X		do_with_delay(glass_time_proc, 2, 0);
X	} else {
X		view(rootfd, srcpr, canvas, mag);
X		do_with_delay(glass_time_proc, 0, delay);
X	}
X}
X
X/*
X * view does the work of displaying the (possibly) magnified image
X * at the location indicated by rootfd (mouse). view copies srcpr to dstpw.
X */
static	void
view(rootfd, srcpr, canvas, mag)
X	int rootfd;		/* root window, for mouse data */	
X	struct pixrect *srcpr;		/* screen source pixrect */
X	Canvas canvas;
X	int mag;
X{
X	/* constants */
X	int maxy = (srcpr->pr_size.y);
X	int maxx = (srcpr->pr_size.x);
X	Pixwin *dstpw = canvas_pixwin(canvas);
X
X	/* local vars */	
X	int x,y;
X	int w, h;
X
X	/* 
X	 * read mouse coords from vuid register.  sadly, the sunview
X	 * programmers guide is not clear on this.  appendix A tells some,
X	 * but you have to look at <sundev/vuid_event.h> to see what
X 	 * virtual events you can find out about.  luckily, the mouse is
X	 * one of them.
X	 */
X	if (locked) {
X		x = locked_x;
X		y = locked_y;
X	} else {
X		x = win_get_vuid_value(rootfd, LOC_X_ABSOLUTE);
X		y = win_get_vuid_value(rootfd, LOC_Y_ABSOLUTE);
X	}
X
X	/* 
X	 * find out how big our drawing surface is.
X	 */
X	w = (int) window_get(canvas, CANVAS_WIDTH);
X	h = (int) window_get(canvas, CANVAS_HEIGHT);
X
X	/*
X	 * draw on it.
X	 */
X	if (mag<=1) {
X		x = min(maxx-w, max(x-w, 0));
X		y = min(maxy-h, max(y-h, 0));
X		update(dstpw, 0, 0, w, h, PIX_SRC, srcpr, x, y);
X	}
X	else {
X		x = min(maxx-w/mag, max(x-w/mag, 0));
X		y = min(maxy-h/mag, max(y-h/mag, 0));
X		pw_mag(dstpw, 0, 0, w, h, mag, srcpr, x, y);
X	}
X}
X
X/*
X * pw_mag copies a magnified view of spr to dpw using pixel replication.
X * the arguments are the same as those to the pw_rop library call, except
X * that magnification is passed instead of raster-op.
X */
static	void
pw_mag(dpw, dx, dy, w, h, mag, spr, sx, sy)
X	Pixwin *dpw;	/* destination pixwin */
X	int dx, dy;  	/* destination x,y */
X	int w, h;	/* width and height of block to copy */
X	int mag; 	/* magnification */
X	struct pixrect *spr;	/* source pixrect */
X	int sx,sy;	/* location in source to copy from */
X{
X	/* locals */
X	register int	xmax, ymax ;
X	register int	x, y, delta, cnt ;
X	register int	x0, y0 ;
X	Rect	lock_rect ;
X
X	/* w,h are maximum output (magnified) dimensions; xmax,ymax are
X	   maximum input dimensions, rounded up */
X
X	xmax = (w+mag-1)/mag ;
X	ymax = (h+mag-1)/mag ;
X
X	/* make off-screen copy of source */
X	/* KLUDGE:  pixrect and pixwin operations will interfere with
X	   each other, causing garbage to appear in the canvas if
X	   the cursor is being moved during the pr_rop.  By locking
X	   something (anything) during the pr_rop, we avoid this problem */
X
X	lock_rect.r_left = lock_rect.r_top = 0 ;
X	lock_rect.r_width = w ;  lock_rect.r_height = h ;
X	pw_lock(dpw, &lock_rect) ;
X	pr_rop(tmpdst, 0, 0, xmax, ymax, PIX_SRC|PIX_DONTCLIP, spr, sx, sy);
X	pw_unlock(dpw) ;
X
X
X	delta = xmax*mag - w ;			/* error term */
X	x0 = xmax-1; cnt = mag-delta ;
X	for(x = w-1; x>=0; --x)
X	{
X	  pr_rop(tmpdst, x, 0, 1, ymax, PIX_SRC|PIX_DONTCLIP, tmpdst, x0, 0);
X	  if(--cnt <= 0)
X	  {
X	    cnt = mag ;
X	    --x0 ;
X	  }
X	}
X
X	delta = ymax*mag - h ;			/* error term */
X	y0 = ymax-1; cnt = mag-delta ;
X	for(y = h-1; y>=0; --y)
X	{
X	  pr_rop(tmpdst, 0, y, w, 1, PIX_SRC|PIX_DONTCLIP, tmpdst, 0, y0);
X	  if(--cnt <= 0)
X	  {
X	    cnt = mag ;
X	    --y0 ;
X	  }
X	}
X
X
X	/* draw */
X	update(dpw, dx, dy, w, h, PIX_SRC, tmpdst, 0, 0);
X}
X
X/* for debugging purposes, mostly */
static	void
update(dpw, dx, dy, w, h, mag, spr, sx, sy)
X	Pixwin *dpw;	/* destination pixwin */
X	int dx, dy;  	/* destination x,y */
X	int w, h;	/* width and height of block to copy */
X	int mag; 	/* magnification */
X	struct pixrect *spr;
X	/* source pixrect */
X	int sx,sy;	/* location in source to copy from */
X{
pw_rop(dpw, dx, dy, w, h, mag, spr, sx, sy);
X}
X
X
X/* 
X * a service routine that gets called when the frame is destroyed
X * by someone selecting 'quit'.  this is basically right out of the 
X * manual.
X */
static Notify_value
notice_destroy_event(frame, status)
X	Frame *frame;
X	Destroy_status status;
X{
X	if (status != DESTROY_CHECKING) {
X		done = 1;
X	}
X	return (notify_next_destroy_func(frame,status));
X}
X
X/*
X * The routines below I have found enormously handy when dispatching
X * things via the notifier.  Use them in good health, or bad.  I do.
X *		-mark weiser
X */
X
X/*
X * Call procedure f in a little while.
X */
do_with_delay(f, secs, usecs)
void (*f)();
int secs, usecs;
X{
X	Notify_value do_the_call();
X	struct itimerval timer;
X
X	/* Sigh, so much work just to wait a bit before starting up. */
X	timer.it_interval.tv_usec = 0;
X	timer.it_interval.tv_sec = 0;
X	timer.it_value.tv_usec = usecs;
X	timer.it_value.tv_sec = secs;
X	notify_set_itimer_func(f, do_the_call,
X		ITIMER_REAL, &timer, NULL);
X}
X
X/*
X * Wrapper to make sure procedures from do_with_delay return good values
X * to the notifier.
X */
Notify_value
do_the_call(f, which)
void (*f)();
X{
X	(*f)();
X	return NOTIFY_DONE;
X}
X
static	Notify_value
update_mag_proc(item, value)
X	Panel_item	item;
X	int		value ;
X{
X	int	width, height ;
X	width = (int) window_get(canvas, WIN_WIDTH) ;
X	height = (int) window_get(canvas, WIN_HEIGHT) ;
X	mag = value;
X	resize_proc(canvas, width, height) ;
X	return NOTIFY_DONE;
X}
X
X
static	Notify_value
update_value_proc(item, value)
X	Panel_item	item;
X	int		value ;
X{
X	int *ptr;
X	ptr = (int *)panel_get(item, PANEL_CLIENT_DATA);
X	*ptr = value;
X	return NOTIFY_DONE;
X}
X
static	void
lock_proc(item, event)
X	Panel_item;
X	Event *event;
X{
X	extern void do_the_lock();
X	popup_msg(frame, event, 
X		"After buttoning 'Done' in this window,\n\
you will have ten (10) seconds to put the\n\
cursor someplace.  At the end of 10 seconds,\n\
glass will be locked into looking at that position.");
X	locked = 0;
X}
X
static	void
unlock_proc()
X{
X	locked = 0;
X}
X
static	void
do_the_lock()
X{
X	static void popup_textsw_done();
X	locked_x = win_get_vuid_value(rootfd, LOC_X_ABSOLUTE);
X	locked_y = win_get_vuid_value(rootfd, LOC_Y_ABSOLUTE);
X	locked = 1;
X}
X
X/*
X * The stuff below is some standard hacks I have started using,
X * especially in the 'sdi' game.  I have inserted them here for convenience.
X *		-mark weiser
X */
X
static Frame popup_frame = NULL;
static Textsw popup_text;
static Panel popup_panel;
static Panel_item popup_msg_item;
static void popup_yes_proc(), popup_no_proc(), popup_textsw_done();
X
X/*
X * Fake an event, so anyone can popup a message. 
X */
easy_pop(msg)
char *msg;
X{
X	Event event;
X	event_x(&event) = (int)window_get(frame, WIN_X); 
X	event_y(&event) = (int)window_get(frame, WIN_Y);
X	popup_msg(frame, &event, msg);
X}
X
X/*
X * Pop up a message inside a textsw.  Since textsw's don't really
X * popup (in SunOS 3.2), just display it and put up a 'done' button
X * to kill it when the user is done.
X * Frame should be the frame in which Event occured.  Msg can
X * contain imbedded newlines.
X */
popup_msg(frame, event, msg)
XFrame *frame;
XEvent *event;
char *msg;
X{
X	int lines = count_lines(msg);
X	if (popup_frame != NULL) {
X		/* Can only do one of these at a time. */
X		return;
X	}
X	init_popup_msg(frame, msg, lines);
X	textsw_insert(popup_text, msg, strlen(msg));
X	window_set(popup_frame, WIN_X, event_x(event),
X		WIN_Y, event_y(event),
X		WIN_SHOW, TRUE,
X		0);
X}
X
X/*
X * A helper proc to do all the work of window creation for message popups
X */
init_popup_msg(baseframe, msg, lines)
XFrame baseframe;
char *msg;
X{
X	popup_frame = window_create(baseframe, FRAME,
X		WIN_ERROR_MSG, "Can't create window.",
X		0);
X	popup_panel = window_create(popup_frame, PANEL,
X		/* WIN_BELOW, popup_text, */
X		WIN_X, ATTR_COL(0),		/* bug workaround, should not be necessary */
X		0);
X	panel_create_item(popup_panel, PANEL_BUTTON,
X		PANEL_LABEL_IMAGE, panel_button_image(popup_panel, "Done", 4, NULL),
X		PANEL_NOTIFY_PROC, popup_textsw_done,
X		0);
X	window_fit(popup_panel);
X	popup_text = window_create(popup_frame, TEXTSW,
X		WIN_ERROR_MSG, "Can't create window.",
X		WIN_ROWS, min(30, lines),
X		WIN_COLUMNS, max_line(msg)+3,
X		TEXTSW_IGNORE_LIMIT, TEXTSW_INFINITY,
X		TEXTSW_CONTENTS, msg,
X		TEXTSW_BROWSING, TRUE,
X		TEXTSW_DISABLE_LOAD, TRUE,
X		TEXTSW_DISABLE_CD, TRUE,
X		0);
X	window_fit(popup_frame);
X}
X
void
timeout_proc()
X{
X	int val = (int)panel_get_value(time_left_item);
X	if (val > 0) {
X		panel_set(time_left_item, PANEL_VALUE, val-1, 0);
X		do_with_delay(timeout_proc, 1, 0);
X	} else {
X		panel_set(time_left_item, PANEL_SHOW_ITEM, FALSE, 0);
X		panel_paint(panel, PANEL_CLEAR);
X		do_the_lock();
X	}
X}
X
X/* A helper for killing message popups. */
static void
popup_textsw_done()
X{
X	window_set(popup_frame, FRAME_NO_CONFIRM, TRUE, 0);
X	window_destroy(popup_frame);
X	popup_frame = NULL;
X	panel_set(time_left_item, PANEL_SHOW_ITEM, TRUE, PANEL_VALUE, 10, 0);
X	do_with_delay(timeout_proc, 1, 0);
X}
X
X/*
X * Find the size of the longest line in a string of lines separated by newlines
X */
max_line(s)
char *s;
X{
X	int max = 0, count = 0;
X	while (*s) {
X		if (*s++ == '\n') {
X			if (count > max)
X				max = count;
X			count = 0;
X			continue;
X		}
X		count += 1;
X	}
X	if (count > max)
X		max = count;
X	return max;
X}
X
X/*
X * Count the number of lines in a string of lines separated by newlines.
X */
count_lines(s)
char *s;
X{
X	int count = 0;
X	while (*s) {
X		if (*s++ == '\n')
X			count += 1;
X	}
X	return count+1;
X}
X
X/* need functions, not macros, because of non-idempotent funcall arguments */
max(x,y)
X{
X	return x<y ? y : x;
X}
X
min(x,y)
X{
X	return x<y ? x : y;
X}
END_OF_FILE
if test 16203 -ne `wc -c <'src/glass.c'`; then
    echo shar: \"'src/glass.c'\" unpacked with wrong size!
fi
# end of 'src/glass.c'
fi
echo shar: End of archive 7 \(of 10\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 10 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0