[alt.sources] STDWIN 0.9.5, Part 06/19

guido@cwi.nl (Guido van Rossum) (03/04/91)

Archive-name: stdwin/part06

#! /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 6 (of 19)."
# Contents:  Appls/dpv/dpvoutput.c Doc/ABOUT Packs/textedit/textedit.c
#   Ports/x11/dialog.c
# Wrapped by guido@voorn.cwi.nl on Mon Mar  4 12:37:25 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Appls/dpv/dpvoutput.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Appls/dpv/dpvoutput.c'\"
else
echo shar: Extracting \"'Appls/dpv/dpvoutput.c'\" \(5954 characters\)
sed "s/^X//" >'Appls/dpv/dpvoutput.c' <<'END_OF_FILE'
X/* dpv -- ditroff previewer.  Output functions. */
X
X#include "dpv.h"
X#include "dpvmachine.h"
X#include "dpvoutput.h"
X
XWINDOW	*win;			/* output window */
X
X/* Scale factors (must be longs to avoid overflow) */
X
Xlong	hscale, hdiv;		/* Horizontal scaling factors */
Xlong	vscale, vdiv;		/* Vertical scaling factors */
X
Xint paperwidth, paperheight;	/* Paper dimenmsions */
X
X/* Variables used to make put1(c) as fast as possible */
X
Xint	topdraw, botdraw;	/* Top, bottom of rect to redraw */
Xint	baseline;		/* Caches wbaseline() */
Xint	lineheight;		/* Caches wlineheight() */
Xint	doit;			/* Set if output makes sense */
Xint	vwindow;		/* Caches VWINDOW - baseline */
X
Xextern void	drawproc();	/* Draw procedore, in dpvcontrol.c */
X
X/* Create the window */
X
Xinitoutput(filename)
X	char *filename;
X{
X	int winwidth, winheight;
X	int hmargin, vmargin;
X	
X	setscale();
X	wsetdefwinsize(paperwidth, paperheight);
X	win= wopen(filename, drawproc);
X	wsetdocsize(win, paperwidth, paperheight);
X	wsetwincursor(win, wfetchcursor("arrow"));
X	
X	/* Center the window in the document */
X	wgetwinsize(win, &winwidth, &winheight);
X	hmargin = (paperwidth - winwidth) / 2;
X	if (hmargin < 0)
X		hmargin = 0;
X	vmargin = (paperheight - winheight) / 2;
X	if (vmargin < 0)
X		vmargin = 0;
X	wshow(win, hmargin, vmargin,
X				paperwidth - hmargin, paperheight - hmargin);
X}
X
X/* Compute scale factors from screen dimensions and device resolution.
X   Call before outputting anything, but after input device resolution
X   is known. */
X
Xstatic
Xsetscale()
X{
X	int scrwidth, scrheight, mmwidth, mmheight;
X	int hdpi, vdpi;
X	
X	wgetscrsize(&scrwidth, &scrheight);
X	wgetscrmm(&mmwidth, &mmheight);
X	hdpi = scrwidth * 254L / 10 / mmwidth;
X	vdpi = scrheight * 254L / 10 / mmwidth;
X	if (dbg) {
X		printf("screen %dx%d pixels, %dx%d mm.\n",
X			scrwidth, scrheight, mmwidth, mmheight);
X		printf("dots per inch %dx%d\n", hdpi, vdpi);
X	}
X	/* Adjust mm sizes to 75x75 dpi if a resolution less than 75 dpi
X	   is reported (some servers lie!) */
X	if (hdpi < 75) {
X		fprintf(stderr,
X			"Adjusting horizontal resolution to 75 dpi\n");
X		mmwidth = scrwidth * 254L / 750;
X	}
X	if (vdpi < 75) {
X		fprintf(stderr,
X			"dpv: Adjusting vertical resolution to 75 dpi\n");
X		mmheight = scrheight * 254L / 750;
X	}
X	/* Dots/mm == scrwidth/mmwidth, etc.; there are 25.4 mm/inch */
X	hscale= 254L * scrwidth / 10;
X	hdiv= mmwidth * res;
X	vscale= 254L * scrheight / 10;
X	vdiv= mmheight * res;
X	/* Set desired width & height of paper */
X	paperwidth= 210 * scrwidth / mmwidth;
X	paperheight= 297 * scrheight / mmheight;
X	if (dbg) {
X		printf("hscale=%d, hdiv=%d, vscale=%d, vdiv=%d\n",
X			hscale, hdiv, vscale, vdiv);
X		printf("paper %dx%d\n", paperwidth, paperheight);
X	}
X}
X
X/* Force a redraw event for the entire window.
X   Used after a new page is made current. */
X
Xchangeall()
X{
X	wchange(win, 0, 0, paperwidth, paperheight);
X}
X
X/* Recompute doit & vwindow.
X   Call after each font change and each vertical move.
X   Assumes topdraw and botdraw are set by drawproc(),
X   and lineheight and baseline are set by usefont(). */
X
Xrecheck()
X{
X	if (ipage != showpage)
X		doit= FALSE;
X	else {
X		vwindow= VWINDOW - baseline;
X		doit= vwindow < botdraw && vwindow+lineheight > topdraw;
X	}
X}
X
X/* Output a funny character, called in response to 'Cxx' input.
X   Don't rely on 'doit'; the character might be in a different font,
X   invalidating the clipping computations in recheck(). */
X
Xput1s(s)
X	char *s;
X{
X	if (ipage == showpage)
X		drawfunny(s);
X}
X
X/* Line drawing functions.
X   There really do some of the work that belongs in dpvmachine.c,
X   and even dpvparse.c. */
X
Xdrawline(dh, dv)
X	int dh, dv;
X{
X	if (ipage == showpage)
X		wdrawline(HWINDOW, VWINDOW, HWIN(hpos+dh), VWIN(vpos+dv));
X	hpos += dh;
X	vpos += dv;
X}
X
Xdrawcirc(diameter)
X	int diameter;
X{
X	if (ipage == showpage)
X		wdrawcircle(HWIN(hpos+diameter/2), VWINDOW,
X			(int)(diameter/2*hscale/hdiv));
X	/* I assume hpos, vpos remain unchanged here */
X}
X
Xdrawellip(haxis, vaxis)
X	int haxis, vaxis;
X{
X	if (ipage == showpage) {
X		wdrawelarc(HWIN(hpos+haxis/2), VWIN(vpos),
X			(int) (haxis*hscale/hdiv/2),
X			(int) (vaxis*vscale/vdiv/2),
X			0, 360);
X	}
X}
X
X#define PI 3.1415726
X
Xdrawarc(n, m, n1, m1)
X/*	current position is start of arc
X *	n,m is position of center relative to current
X *	n1,m1 is intersection point of tangents at start- and endpoints
X *	of the arc
X */
X{
X	double rad, angle1, angle2, sqrt(), atan2(), c;
X	int iang1, iang2;
X	
X	c = 180.0/PI;
X	rad = sqrt((double)((n*n)+(m*m)));
X	angle1 = c*atan2((double)m,(double)-n);
X	angle2 = -2 * (angle1 + c * atan2((double)(m1-m),(double)(n1-n)));
X	iang1 = (int) (angle1 + 0.5);
X	iang2 = (int) (angle2 + 0.5);
X	while (iang1 < 0) iang1 += 360;
X	while (iang2 < 0) iang2 += 360;
X	while (iang1 >= 360) iang1 -= 360;
X	while (iang2 >= 360) iang2 -= 360;
X	/* params for wdrawelarc are
X	 *	x,y for center,
X	 *	horizontal and vertical radii (different for ellipses)
X	 *	start angle in degrees and number of degrees to draw.
X	 *	angles measured anticlockwise from positive x-axis
X	 */
X	if (ipage == showpage)
X		wdrawelarc(HWIN(hpos+n), VWIN(vpos+m),
X			(int)(rad*hscale/hdiv), (int)(rad*vscale/vdiv),
X			iang1, iang2);
X}
X
Xdrawwig(buf, fp, flag)
X	char *buf;
X	FILE *fp;
X{
X	int dh, dv, x = hpos, y = vpos;
X
X	while (getint(&buf, &dh) && getint(&buf, &dv))
X		if (ipage == showpage) {
X			/* HIRO: should always do this (for side effects)? */
X			drawline(x + dh/4 - hpos, y + dv/4 - vpos);
X			drawline(dh / 2, dv / 2);
X			x += dh;
X			y += dv;
X		}
X	drawline(dh / 4, dv / 4);
X	if (index(buf, EOL) == NULL) {
X		int c;
X		/* HIRO: don't know how to do handle this */
X		error(WARNING, "rest of very long wiggly line ignored");
X		do {
X			c = getc(fp);
X		} while (c != EOL && c != EOF);
X	}
X}
X
Xstatic bool
Xgetint(pbuf, px)
X	char **pbuf;
X	int *px;
X{
X	char *buf= *pbuf;
X	while (*buf != EOS && isspace(*buf))
X		++buf;
X	if (*buf == EOS || *buf != '-' && !isdigit(*buf))
X		return FALSE;
X	*px= atoi(buf);
X	while (*buf != EOS && !isspace(*buf))
X		++buf;
X	*pbuf= buf;
X	return TRUE;
X}
END_OF_FILE
if test 5954 -ne `wc -c <'Appls/dpv/dpvoutput.c'`; then
    echo shar: \"'Appls/dpv/dpvoutput.c'\" unpacked with wrong size!
fi
# end of 'Appls/dpv/dpvoutput.c'
fi
if test -f 'Doc/ABOUT' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Doc/ABOUT'\"
else
echo shar: Extracting \"'Doc/ABOUT'\" \(15823 characters\)
sed "s/^X//" >'Doc/ABOUT' <<'END_OF_FILE'
X[Last modified on Sat Apr 15 20:19:00 MET DST 1989 by guido]
X
X
X0. Copyright Notice
X
XSTDWIN is copyrighted: Copyright (c) 1988, 1989 by Stichting Mathematisch
XCentrum, Amsterdam, The Netherlands.  STDWIN is available for
Xnoncommercial use only, free of charge, and with no guarantees.  It can
Xbe freely used and distributed provided these restrictions are honoured.
X
X
X1. Target systems
X
XSTDWIN is aimed at C programs.  It consists of a few header files (of
Xwhich only one is visible to the user) and a library.  In most cases
Xsome system-provided libraries must also be used in the linking phase.
X
XCurrently, full STDWIN is available for the following environments:
X
X(Note that in all cases the code is in beta test state; there may be
Xbugs, functionality may change slightly in the future and new
Xfunctionality may be added, but the basic framework isn't going to
Xchange much.)
X
X*       X version 11, release 3 (should still work with release 2)
X*       Apple Macintosh, using either THINK C (3.01) or MPW C (2.02)
X*       Atari ST, using Mark Williams C (2.1)
X
XYou may volunteer to create a version for your favourite system, or to
Xport it to your favourite C compiler for one of the mentioned micros.
X(The micro versions are rather compiler-dependent, due to the many
Xdifferences between compilers and especially libraries.  Expect
Xdifficulties if you have another compiler or version than the ones
Xmentioned.  Especially the Atari version is flakey.)
X
XA subset, emulating most of STDWIN's functionality on an alphanumeric
Xdisplay (excluding line drawing, but including multiple (non-overlapping)
Xwindows, menus, text editing etc.) is available for:
X
X*       Any decent Unix that has termcap (tested with 4.{2,3} BSD)
X*       MS-DOS, using the Microsoft C compiler (4.0)
X
XSorry, there are no versions yet for SunTools, SunView, NeWS, X10,
XMS-Windows, Presentation Manager or the Amiga.  A hacker might be able
Xto turn the Atari ST version into a general GEM version.  The code is
Xremarkably portable to different processor types and various Unix
Xflavors, as long as they are derived from 4.xBSD.
X
X
X2. Getting the full scoop
X
XI have written a paper about STDWIN which has been published as a
XCWI report (Guido van Rossum: STDWIN -- A Standard Window System
XInterface.  Centre for Mathematics and Computer Science, report
XCS-R8817.  Amsterdam, 1988).
X
XYou can also get a source version for any or all of the above-mentioned
Xsystems.  This is essentially a directory dump of my working version,
Xuntil I have the time or get some help to prepare a real distribution.
XIt is available through anonymous ftp access from uunet.uu.net.
XThe directory is amiga-sources/stdwin (thanks to the moderator, Peter
Xda Silva) get the file README.txt for further instructions.  A version
Xof this file is in ABOUT.txt.  (The version on gatekeeper no longer
Xexists, although it may be revived in the near future).
X
XDistribution to to non-ftp-users is solely by electronic mail.  Be
Xprepared to receive up to half a megabyte (in 32K pieces in "shar"
Xformat).  If you're interested, write to guido@cwi.nl.
X
X
X3. Basic functionality
X
XSTDWIN allows multiple "full-function" windows, roughly in Macintosh
Xstyle (title bar, grow box, close box, scroll bars).  The appearance of
Xwindows is determined by the default of the underlying window manager,
Xand so are other limitations (e.g., overlapping, maximum size, etc.).
XWindows are dynamically created and destroyed by the application, never
Xdirectly by the user or the window manager.
X
XSTDWIN uses a coordinate system derived from the display's coordinate
Xsystem: (0, 0) is top left, with X pointing right and Y pointing down
X(these are actually called h and v).  Pixel size is that of the display.
XThere are enquiry functions to ask for the display size in pixels and in
Xmillimeters.
X
XThe application is responsible for redrawing the window contents when it
Xis exposed.  This is done by associating a "draw procedure" with each
Xwindow, which knows how to draw the entire window's contents.  It gets
Xpassed a pointer to the window and the coordinates of the rectangle that
Xneeds to be redrawn, so it can (although it needn't) restrict itself to
Xthat area.  STDWIN guarantees that a window's redraw procedure is only
Xcalled while the application is waiting for an input event (most
Ximplementations simply turn exposure events into calls to the draw
Xprocedure).
X
XIf the application wants to change part of the graphics it is
Xdisplaying, this is usually done in a two-phase process: first, STDWIN
Xis told that a particular area of the screen must be changed; later,
Xwhen the application starts waiting for input events again, the draw
Xprocedure is called to update the indicated area (and any other area
Xthat was exposed or damaged in some way).
X
XThe application defines the width and height of the area it wants to
Xdraw; this needn't bear any relation to the window or screen size.  This
Xarea is called the "document" although you may also think of it as a
Xvirtual window.  The actual window generally displays a sub-area of the
Xdocument; the window's scroll bars indicate the position of the window
Xwith respect to the document.  The application always uses the
Xcoordinates of its document; STDWIN performs the translation to window
Xor screen coordinates are required by the window manager, and ensures
Xclipping of all output to the window.
X
XSTDWIN is event-based.  An application is expected to have a main loop
Xcontaining a "get event" call followed by a switch on the event type.
XThere is no event mask; an application can simply ignore events it isn't
Xinterested in.  The most important event types are:
X
XACTIVATE:       A window becomes active (keyboard attached and/or topmost)
X
XCHAR:           ASCII character key pressed (except BS, TAB, CR)
X
XCOMMAND:        special key or function (CLOSE, TAB, RETURN, BS, CANCEL,
X                arrow keys etc.)
X
XMOUSE:          MOUSE DOWN, MOUSE MOVE (only while down), MOUSE UP;
X                fields in the event record indicate the h, v position,
X                the number of the button, and the "click number" if the
X                event is potentially part of a multiple-click sequence
X
XMENU:           menu id and item number of a menu selection
X
XSIZE:           user has resized the window
X
XTIMER:          the window's timer went off; each window has one
X                programmable timer which can be set to go off at N/10
X                seconds in the future.  When the timer goes off a TIMER
X                event is returned.
X
XNormally, STDWIN draws text in a single font.  The actual font used
Xdepends on the underlying window manager (and can sometimes be
Xinfluenced by the application programmer and/or the end user in a
Xsystem-dependent manner).  The font may be proportionally spaced, and
Xthere are enquiry functions to find out the dimensions of characters and
Xstrings.  There are also functions to change the font name and point
Xsize dynamically; but these work different in different systems,
Xespecially the allowed font names differ drastically.  This feature is
Xused with some success in the ditroff previewer that is supplied as a
Xdemo.
X
XThere are functions to draw text and simple lines, rectangles and
Xcircles, and ways to erase, shade or invert rectangular areas.  There is
Xno way (yet) to do general bitblt operations, or to influence the pen
Xshape.
X
X
X4. Higher level functionality
X
XSTDWIN provides a blinking vertical bar which can be used to indicate
Xthe text insertion point, so the application needn't use TIMER events to
Xdo the blinking.
X
XSTDWIN provides Macintosh-style menus.  Each window has its own set of
Xmenus, although by default all menus apply to all windows.  A reasonably
Xnumber of menus per window is allowed, each with a reasonable number of
X(textual) menu items.  Menus can be changed dynamically.  Items can be
Xenabled or disabled, and a 'tick mark' can be placed in front of an
Xitem.  Each menu item may have a shortcut character, which, when typed
Xin combination with some system-defined meta key (e.g., ALT or an ESC-
Xprefix) selects the menu item (if enabled).  Menu selection is done
Xcompletely "underwater"; all the application notices are MENU events.
X
XSTDWIN has a few simple routines to display Mac-style "dialog boxes",
Xe.g., to show an error message, or to ask a yes/no question or to ask
Xfor a string to be typed.  There is also a predefined function to ask
Xfor a file name, which may allow the user to browse the file system in
Xsome implementations.
X
XSTDWIN comes with a package built on top of the basic functionality, to
Xedit arbitrary blocks of text (cf. Macintosh TEXTEDIT).  In the future,
Xmore packages will be provided, e.g., a package to provide a simple file
Xeditor (available now!), a package to display a scrolling list of items,
Xa package to define a list of arbitrary labeled "buttons", and a package
Xto simplify the binding of menus to functions somewhat, and a VT100
Xemulator (available now!).
X
X
X5. Function definitions
X
XHere follows a slightly edited listing of the <stdwin.h> header file,
Xwhich more or less documents all available functions and data
Xstructures.  Note that the argument lists are given here as ANSI C
Xprototypes (untested).
X
X#define bool int
X
Xvoid winit();
Xvoid wdone();
X
Xvoid wsetdefwinsize(int width, int height);
Xvoid wsetdefwinpos(int h, int v);
X
X#define MENU struct menu
X
X/* The contents of a text attributes struct are disclosed here because
X   the interface allows the programmer to declare objects of this type.
X   (I'm not so sure anymore that this is the right thing to do!) */
X
Xstruct textattr {
X        short font;
X        unsigned char size;
X        unsigned char style;
X};
X
X#define TEXTATTR struct textattr
X
X#ifndef WINDOW
X
Xstruct window {
X        short tag;
X};
X
X#define WINDOW struct window
X
X#endif
X
XWINDOW *wopen(char *title, void drawproc();
Xvoid wclose(WINDOW *win);
X#define wgettag(win) ((win)->tag)
X#define wsettag(win, newtag) ((win)->tag= newtag)
Xvoid wsetactive(WINDOW *win);
XWINDOW *wgetactive();
Xvoid wgetwinsize(WINDOW *win, int *width, int *height);
Xvoid wsetdocsize(WINDOW *win, int width, int height);
Xvoid wsettitle(WINDOW *win, char *title);
X
Xvoid wsetorigin(WINDOW *win, int h, int v);
Xvoid wshow(WINDOW *win, int left, int top, int right, int bottom);
Xvoid wchange(WINDOW *win, int left, int top, int right, int bottom);
Xvoid wscroll(WINDOW *win, int left, int top, int right, int bottom,
X        int dh, int dv);
X
Xvoid wfleep();
Xvoid wmessage(char *str);
Xvoid wperror(char *name);
Xbool waskstr(char *prompt, char *buf, int buflen);
Xint waskync(char *question, int dflt);
Xbool waskfile(char *prompt, char *buf, int buflen, bool new);
X
Xvoid wsetcaret(WINDOW *win, int h, int v);
Xvoid wnocaret(WINDOW *win);
X
Xvoid wsettimer(WINDOW *win, int deciseconds);
X
XMENU *wmenucreate(int id, char *title);
Xvoid wmenudelete(MENU *mp);
Xint wmenuadditem(MENU *mp, char *text, char shortcut);
Xvoid wmenusetitem(MENU *mp, int i, char *text);
Xvoid wmenusetdeflocal(bool local);
Xvoid wmenuattach(WINDOW *win, MENU *mp);
Xvoid wmenudetach(WINDOW *win, MENU *mp);
X
X/* EVENT STRUCT DEFINITION */
X
Xstruct event {
X        int type;
X        WINDOW *window;
X        union {
X        /* case WE_CHAR: */
X                int character;
X        /* case WE_COMMAND: */
X                int command;
X        /* case WE_MENU: */
X                struct { int id; int item; } m;
X        /* case WE_DRAW: */
X                struct { int left, top, right, bottom; } area;
X        /* case WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP: */
X                struct {
X                        int v;
X                        int h;
X                        int clicks;
X                        int button;
X                        int mask;
X                } where;
X        } u;
X};
X
X#define EVENT struct event
X
X/* Event types */
X
X#define WE_NULL         0       /* (Used internally) */
X#define WE_ACTIVATE     1       /* Window became active */
X#define WE_CHAR         2       /* Character typed at keyboard */
X#define WE_COMMAND      3       /* Special command, function key etc. */
X#define WE_MOUSE_DOWN   4       /* Mouse button pressed */
X#define WE_MOUSE_MOVE   5       /* Mouse moved with button down */
X#define WE_MOUSE_UP     6       /* Mouse button released */
X#define WE_MENU         7       /* Menu item selected */
X#define WE_SIZE         8       /* Window size changed */
X#define WE_MOVE         9       /* (Reserved) */
X#define WE_DRAW         10      /* Request to redraw part of window */
X#define WE_TIMER        11      /* Window's timer went off */
X#define WE_DEACTIVATE   12      /* Window became inactive */
X
X/* Command codes for WE_COMMAND.
X   Special ways of entering these are usually available,
X   such as clicking icons, standard menu items or special keys.
X   Some ASCII keys are also passed back as commands since they
X   more often than not need special processing. */
X
X#define WC_CLOSE        1       /* Should become a separate event! */
X/* The following four are arrow keys */
X#define WC_LEFT         2
X#define WC_RIGHT        3
X#define WC_UP           4
X#define WC_DOWN         5
X/* ASCII keys */
X#define WC_CANCEL       6
X#define WC_BACKSPACE    7
X#define WC_TAB          8
X#define WC_RETURN       9
X
Xvoid wgetevent(EVENT *ep);
Xvoid wungetevent(EVENT *ep);
Xvoid wupdate(WINDOW *win);
Xvoid wbegindrawing(WINDOW *win);
Xvoid wenddrawing(WINDOW *win);
Xvoid wflush();
X
Xvoid wdrawline(int h1, int v1, int h2, int v2);
Xvoid wxorline(int h1, int v1, int h2, int v2);
Xvoid wdrawcircle(int h, int v, int radius);
Xvoid wdrawelarc(int h, int v, int radh, int radv, int angle1, int angle2);
Xvoid wdrawbox(int left, int top, int right, int bottom);
Xvoid werase(int left, int top, int right, int bottom);
Xvoid wpaint(int left, int top, int right, int bottom);
Xvoid winvert(int left, int top, int right, int bottom);
Xvoid wshade(int left, int top, int right, int bottom, int percent);
X
Xint wdrawtext(int h, int v, char *str, int len);
Xint wdrawchar(int h, int v, char c);
Xint wlineheight();
Xint wtextwidth(char *str, int len);
Xint wcharwidth(char c);
Xint wtextbreak(char *str, int len, int width);
X
Xvoid wgettextattr(TEXTATTR *attr);
Xvoid wsettextattr(TEXTATTR *attr);
Xvoid wgetwintextattr(WINDOW *win, TEXTATTR *attr);
Xvoid wsetwintextattr(WINDOW *win, TEXTATTR *attr);
X
Xvoid wsetplain();
Xvoid wsethilite();
Xvoid wsetinverse();
Xvoid wsetitalic();
Xvoid wsetbold();
Xvoid wsetbolditalic();
Xvoid wsetunderline();
X
X/* TEXTEDIT PACKAGE DEFINITIONS */
X
X#define TEXTEDIT struct _textedit
X
XTEXTEDIT *tealloc(WINDOW *win, int left, int top, int width);
XTEXTEDIT *tecreate(WINDOW *win,
X        int left, int top, int right, int bottom);
Xvoid tefree(TEXTEDIT *tp);
Xvoid tedestroy(TEXTEDIT *tp);
X
Xvoid tedraw(TEXTEDIT *tp);
Xvoid tedrawnew(TEXTEDIT *tp, int left, int top, int right, int bottom);
Xvoid temove(TEXTEDIT *tp, int left, int top, int width);
Xvoid temovenew(TEXTEDIT *tp,
X        int left, int top, int right, int bottom);
X
Xvoid tesetfocus(TEXTEDIT *tp, int foc1, int foc2);
Xvoid tereplace(TEXTEDIT *tp, char *str);
Xvoid tesetbuf(TEXTEDIT *tp, char *buf, int buflen);
X
Xvoid tearrow(TEXTEDIT *tp, int code);
Xvoid tebackspace(TEXTEDIT *tp);
Xbool teclicknew(TEXTEDIT *tp, int h, int v, bool extend);
Xbool tedoubleclick(TEXTEDIT *tp, int h, int v);
Xbool teevent(TEXTEDIT *tp, EVENT *ep);
X
X#define teclick(tp, h, v) teclicknew(tp, h, v, FALSE)
X#define teclickextend(tp, h, v) teclicknew(tp, h, v, TRUE)
X
Xchar *tegettext(TEXTEDIT *tp);
Xint tegetlen(TEXTEDIT *tp);
Xint tegetnlines(TEXTEDIT *tp);
Xint tegetfoc1(TEXTEDIT *tp);
Xint tegetfoc2(TEXTEDIT *tp);
Xint tegetleft(TEXTEDIT *tp);
Xint tegettop(TEXTEDIT *tp);
Xint tegetright(TEXTEDIT *tp);
Xint tegetbottom(TEXTEDIT *tp);
X
X/* Text paragraph drawing functions: */
X
Xint wdrawpar(int h, int v, char *text, int width);
X        /* Returns new v coord. */
Xint wparheight(char *text, int width);
X        /* Returns height */
END_OF_FILE
if test 15823 -ne `wc -c <'Doc/ABOUT'`; then
    echo shar: \"'Doc/ABOUT'\" unpacked with wrong size!
fi
# end of 'Doc/ABOUT'
fi
if test -f 'Packs/textedit/textedit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Packs/textedit/textedit.c'\"
else
echo shar: Extracting \"'Packs/textedit/textedit.c'\" \(14543 characters\)
sed "s/^X//" >'Packs/textedit/textedit.c' <<'END_OF_FILE'
X/* Text Edit, high level routines */
X
X#include "text.h"
X
Xvoid
Xtereplace(tp, str)
X	TEXTEDIT *tp;
X	char *str;
X{
X	int len= strlen(str);
X	
X	if (len == 1 && teoptinschar(tp, (int) str[0]))
X		return;
X	
X	teinsert(tp, str, len);
X}
X
Xstatic
Xteinschar(tp, c)
X	TEXTEDIT *tp;
X	int c;
X{
X	char cbuf[2];
X	
X	if (teoptinschar(tp, c))
X		return;
X	
X	cbuf[0]= c;
X	cbuf[1]= EOS;
X	teinsert(tp, cbuf, 1);
X}
X
X/* Optimization for the common case insert char.
X   Assumes text measurement is additive. */
X
Xstatic
Xtesetoptdata(tp)
X	TEXTEDIT *tp;
X{
X	lineno i;
X	bufpos k, pos, end;
X	
X	zcheck();
X	zassert(tp->foclen == 0);
X	
X	pos= zaddgap(tp->foc);
X	tp->opt_i= i= tewhichline(tp, pos, FALSE);
X	tp->opt_h= tp->left + tetextwidth(tp, tp->start[i], pos);
X	tp->opt_v= tp->top + i*tp->vspace;
X	end= tp->start[i+1];
X	if (end > pos && zcharbefore(end) == EOL)
X		zdecr(&end);
X	while (end > pos && zcharbefore(end) == ' ')
X		zdecr(&end);
X	for (k= pos; k < end; zincr(&k)) {
X		if (zcharat(k) == '\t')
X			break;
X	}
X	if (k < end) {
X		tp->opt_end=
X			tp->left + tetextwidth(tp, tp->start[i], znext(k));
X		tp->opt_avail= tp->opt_end -
X			(tp->left + tetextwidth(tp, tp->start[i], k));
X	}
X	else {
X		tp->opt_end= tp->right;
X		tp->opt_avail= tp->width - tetextwidth(tp, tp->start[i], end);
X	}
X	if (tp->start[i] > 0 && zcharbefore(tp->start[i]) != EOL) {
X		tp->opt_in_first_word= TRUE;
X		for (k= tp->start[i]; k < pos; zincr(&k)) {
X			if (isspace(zcharat(k))) {
X				tp->opt_in_first_word= FALSE;
X				break;
X			}
X		}
X	}
X	else
X		tp->opt_in_first_word= FALSE;
X	tp->opt_valid= TRUE;
X}
X
Xstatic bool
Xteoptinschar(tp, c)
X	TEXTEDIT *tp;
X	int c;
X{
X	int w;
X	
X	if (tp->foclen != 0 || c == EOL || c == '\t' || tp->focprev)
X		return FALSE;
X	if (!tp->opt_valid)
X		tesetoptdata(tp);
X	if (c == ' ' && tp->opt_in_first_word)
X		return FALSE;
X	w= wcharwidth(c);
X	if (w >= tp->opt_avail)
X		return FALSE;
X	
X	temovegapto(tp, tp->foc);
X	if (tp->gaplen < 1)
X		tegrowgapby(tp, 1+RESERVE);
X	if (tp->start[tp->opt_i] == zgapend)
X		tp->start[tp->opt_i]= tp->gap;
X	++tp->gap;
X	--tp->gaplen;
X	tp->buf[tp->foc]= c;
X	++tp->foc;
X	
X	tp->opt_avail -= w;
X	if (tp->active)
X		wnocaret(tp->win);
X	wscroll(tp->win,
X		tp->opt_h, tp->opt_v,
X		tp->opt_end, tp->opt_v + tp->vspace,
X		w, 0);
X	wbegindrawing(tp->win);
X	wdrawchar(tp->opt_h, tp->opt_v, c);
X	wenddrawing(tp->win);
X	tp->opt_h += w;
X	if (tp->active) {
X		wsetcaret(tp->win, tp->opt_h, tp->opt_v);
X		wshow(tp->win,
X			tp->opt_h, tp->opt_v,
X			tp->opt_h, tp->opt_v + tp->vspace);
X	}
X	tp->aim= tp->opt_h;
X	
X	return TRUE;
X}
X
Xstatic
Xteinsert(tp, str, len)
X	TEXTEDIT *tp;
X	char *str;
X	int len;
X{
X	focpos oldfoc= tp->foc;
X	
X	tehidefocus(tp);
X	temovegapto(tp, zfocend);
X	tp->gap= tp->foc;
X	tp->gaplen += tp->foclen;
X	teemptygap(tp);
X	tp->foclen= 0;
X	if (tp->gaplen < len)
X		tegrowgapby(tp, len-tp->gaplen+RESERVE);
X	strncpy(tp->buf+tp->gap, str, len);
X	tp->gap += len;
X	tp->gaplen -= len;
X	tp->foc += len;
X	terecompute(tp, zaddgap(oldfoc), zaddgap(tp->foc));
X}
X
Xstatic int lasteol;	/* Optimization trick for teendofline */
X
Xstatic
Xterecompute(tp, first, last)
X	TEXTEDIT *tp;
X	int first, last;
X{
X	lineno i;
X	lineno chfirst, chlast; /* Area to pass to wchange */
X	lineno shift= 0; /* Lines to shift down (negative: up) */
X	vcoord newbottom;
X	
X	tp->start[0]= zaddgap(0);
X	
X	i= 2;
X	while (i <= tp->nlines && tp->start[i] < first)
X		++i;
X	i -= 2;
X	chfirst= tp->nlines;
X	chlast= i;
X	lasteol= -1;
X	
X	/* TO DO: scroll up/down if inserting/deleting lines */
X	
X	for (;; ++i) {
X		bufpos end= teendofline(tp, tp->start[i]);
X		bool unchanged= (i < tp->nlines && end == tp->start[i+1]);
X		if (!unchanged)
X			shift += tesetstart(tp, i+1, end, last);
X		if (!(unchanged && end < first)) {
X			if (i < chfirst)
X				chfirst= i;
X			chlast= i+1;
X		}
X		if (end >= tp->buflen) {
X			if (end > tp->start[i] && zcharbefore(end) == EOL)
X				continue;
X			else
X				break;
X		}
X		if (unchanged && end > last) {
X			i= tp->nlines-1;
X			break;
X		}
X	}
X	
X	zassert(tp->nlines > i);
X	
X	if (tp->drawing) {
X		if (shift != 0) {
X			lineno k= chlast;
X			if (shift > 0)
X				k -= shift;
X			wscroll(tp->win,
X				tp->left, tp->top + k*tp->vspace,
X				tp->right, tp->top + tp->nlines*tp->vspace,
X				0, shift*tp->vspace);
X		}
X		
X		wchange(tp->win,
X			tp->left, tp->top + chfirst*tp->vspace,
X			tp->right, tp->top + chlast*tp->vspace);
X	}
X	
X	tp->nlines= i+1;
X	newbottom= tp->top + tp->vspace*tp->nlines;
X	if (newbottom < tp->bottom)
X		wchange(tp->win,
X			tp->left, newbottom, tp->right, tp->bottom);
X	tp->bottom= newbottom;
X	tp->aim= UNDEF;
X	tp->focprev= FALSE;
X	if (tp->drawing)
X		tesetcaret(tp);
X	
X	zcheck();
X}
X
Xstatic int
Xtesetstart(tp, i, pos, last)
X	register TEXTEDIT *tp;
X	register lineno i;
X	bufpos pos, last;
X{
X	if (i > tp->nlines) {
X		tp->nlines= i;
X		if (tp->nlines >= tp->nstart) {
X			tp->nstart= tp->nlines + STARTINCR;
X			tp->start= (bufpos*)zrealloc((char*)tp->start,
X				tp->nstart*sizeof(int));
X		}
X		tp->start[i]= pos;
X		return 0;
X	}
X	else {
X		lineno shift= 0;
X		lineno k;
X		for (k= i; k < tp->nlines; ++k) {
X			if (tp->start[k] > pos)
X				break;
X		}
X		shift= k-1 - i;
X		/* start[k] should really be start[i+1] */
X		if (shift < 0 && tp->start[k] >= last) { /* Insert one */
X			++tp->nlines;
X			if (tp->nlines >= tp->nstart) {
X				tp->nstart= tp->nlines + STARTINCR;
X				tp->start= (int*)zrealloc((char*)tp->start,
X					tp->nstart*sizeof(int));
X			}
X			for (k= tp->nlines; k > i; --k)
X				tp->start[k]= tp->start[k-1];
X		}
X		else if (shift > 0 && pos >= last) { /* Delete some */
X			for (; k <= tp->nlines; ++k)
X				tp->start[k-shift]= tp->start[k];
X			tp->nlines -= shift;
X			if (tp->nlines < tp->nstart - STARTINCR) {
X				tp->nstart= tp->nlines+1;
X				tp->start= (int*)zrealloc((char*)tp->start,
X					tp->nstart*sizeof(int));
X			}
X		}
X		else
X			shift= 0; /* Don't shift (yet) */
X		tp->start[i]= pos;
X		return -shift;
X	}
X}
X
Xstatic int
Xteendofline(tp, pos)
X	TEXTEDIT *tp;
X	bufpos pos;
X{
X	bufpos end= tp->buflen;
X	bufpos k;
X	
X	/* Find first EOL if any */
X	if (lasteol >= pos)
X		k= lasteol;
X	else {
X		for (k= pos; k < end && zcharat(k) != EOL; zincr(&k))
X			;
X		lasteol= k;
X	}
X	
X	end= tetextbreak(tp, pos, k, tp->width);
X	
X	/* Extend with any spaces immediately following end */
X	for (; end < tp->buflen && zcharat(end) == ' '; zincr(&end))
X		;
X	
X	if (end < tp->buflen) {
X		/* Extend with immediately following EOL */
X		if (zcharat(end) == EOL)
X			zincr(&end);
X		else {
X			/* Search back for space before last word */
X			for (k= end; zdecr(&k) >= pos && !isspace(zcharat(k)); )
X				;
X			
X			if (k >= pos)
X				end= znext(k);
X		}
X	}
X
X	/* Each line must be at least one character long,
X	   otherwise a very narrow text-edit box would cause
X	   the size calculation to last forever */
X	if (end == pos && end < tp->buflen)
X		zincr(&end);
X	
X	return end;
X}
X
Xbool
Xteevent(tp, e)
X	TEXTEDIT *tp;
X	EVENT *e;
X{
X	if (e->window != tp->win)
X		return FALSE;
X	
X	switch (e->type) {
X	
X	case WE_CHAR:
X		teinschar(tp, e->u.character);
X		break;
X	
X	case WE_COMMAND:
X		switch (e->u.command) {
X		case WC_BACKSPACE:
X			tebackspace(tp);
X			break;
X		case WC_RETURN:
X			teinschar(tp, EOL);
X			break;
X		case WC_TAB:
X			teinschar(tp, '\t');
X			break;
X		case WC_LEFT:
X		case WC_RIGHT:
X		case WC_UP:
X		case WC_DOWN:
X			tearrow(tp, e->u.command);
X			break;
X		default:
X			return FALSE;
X		}
X		break;
X	
X	case WE_MOUSE_DOWN:
X		{
X			int h= e->u.where.h, v= e->u.where.v;
X			if (h >= tp->left && h <= tp->right &&
X					v >= tp->top && v <= tp->bottom)
X				teclicknew(tp, h, v,
X					e->u.where.button == 2,
X					e->u.where.clicks > 1);
X			else
X				return FALSE;
X		}
X		break;
X	
X	case WE_MOUSE_MOVE:
X	case WE_MOUSE_UP:
X		if (!tp->mdown)
X			return FALSE;
X		teclicknew(tp, e->u.where.h, e->u.where.v, TRUE, tp->dclick);
X		if (e->type == WE_MOUSE_UP)
X			tp->mdown= FALSE;
X		break;
X	
X	case WE_DRAW:
X		wbegindrawing(tp->win);
X		tedrawnew(tp, e->u.area.left, e->u.area.top,
X				e->u.area.right, e->u.area.bottom);
X		wenddrawing(tp->win);
X		break;
X	
X	default:
X		return FALSE;
X	
X	}
X	
X	/* If broke out of switch: */
X	return TRUE;
X}
X
Xvoid
Xtearrow(tp, code)
X	TEXTEDIT *tp;
X	int code;
X{
X	lineno i;
X	bufpos pos;
X	
X	tehidefocus(tp);
X	
X	switch (code) {
X	
X	case WC_LEFT:
X		if (tp->foclen != 0)
X			tp->foclen= 0;
X		else {
X			if (tp->foc > 0)
X				--tp->foc;
X			else
X				wfleep();
X		}
X		tp->aim= UNDEF;
X		tp->focprev= FALSE;
X		break;
X	
X	case WC_RIGHT:
X		if (tp->foclen != 0) {
X			tp->foc += tp->foclen;
X			tp->foclen= 0;
X		}
X		else {
X			if (tp->foc < tp->buflen-tp->gaplen)
X				++tp->foc;
X			else
X				wfleep();
X		}
X		tp->aim= UNDEF;
X		tp->focprev= FALSE;
X		break;
X	
X	/* TO DO: merge the following two cases */
X	
X	case WC_UP:
X		if (tp->foclen > 0)
X			tp->foclen= 0;
X		else {
X			pos= zaddgap(tp->foc);
X			i= tewhichline(tp, pos, (bool) tp->focprev);
X			if (i <= 0)
X				wfleep();
X			else {
X				if (tp->aim == UNDEF)
X					tp->aim= tp->left + tetextwidth(tp,
X						tp->start[i], pos);
X				--i;
X				pos= tetextround(tp, i, tp->aim);
X				tp->foc= zsubgap(pos);
X				tp->focprev= (pos == tp->start[i+1]);
X			}
X		}
X		break;
X	
X	case WC_DOWN:
X		if (tp->foclen > 0) {
X			tp->foc += tp->foclen;
X			tp->foclen= 0;
X		}
X		else {
X			pos= zaddgap(tp->foc);
X			i= tewhichline(tp, pos, (bool) tp->focprev);
X			if (i+1 >= tp->nlines)
X				wfleep();
X			else {
X				if (tp->aim == UNDEF)
X					tp->aim= tp->left + tetextwidth(tp,
X						tp->start[i], pos);
X				++i;
X				pos= tetextround(tp, i, tp->aim);
X				tp->foc= zsubgap(pos);
X				tp->focprev= (pos == tp->start[i+1]);
X			}
X		}
X		break;
X	
X	default:
X		dprintf("tearrow: bad code %d", code);
X		break;
X		
X	}
X	tesetcaret(tp);
X}
X
Xvoid
Xtebackspace(tp)
X	TEXTEDIT *tp;
X{
X	if (tp->foclen == 0) {
X		if (tp->foc == 0) {
X			wfleep();
X			return;
X		}
X		--tp->foc;
X		tp->foclen= 1;
X	}
X	teinsert(tp, "", 0);
X}
X
Xbool
Xteclicknew(tp, h, v, extend, dclick)
X	TEXTEDIT *tp;
X	coord h, v;
X	bool extend, dclick;
X{
X	lineno i;
X	bufpos pos;
X	focpos f;
X	
X	tp->dclick= dclick;
X	pos= tewhereis(tp, h, v, &i);
X	f= zsubgap(pos);
X	if (extend) {
X		if (!tp->mdown) {
X			tp->mdown= TRUE;
X			if (f - tp->foc < tp->foc + tp->foclen - f)
X				tp->anchor= tp->foc + tp->foclen;
X			else
X				tp->anchor= tp->foc;
X			tp->anchor2= tp->anchor;
X		}
X		if (f >= tp->anchor) {
X			if (dclick)
X				f= tewordend(tp, f);
X			techangefocus(tp, tp->anchor, f);
X		}
X		else {
X			if (dclick)
X				f= tewordbegin(tp, f);
X			techangefocus(tp, f, tp->anchor2);
X		}
X	}
X	else {
X		tp->mdown= TRUE;
X		tp->anchor= tp->anchor2= f;
X		if (dclick) {
X			tp->anchor= tewordbegin(tp, tp->anchor);
X			tp->anchor2= tewordend(tp, f);
X		}
X		techangefocus(tp, tp->anchor, tp->anchor2);
X	}
X	tp->aim= UNDEF;
X	tp->focprev= (tp->foclen == 0 && pos == tp->start[i+1]);
X	tesetcaret(tp);
X	return TRUE;
X}
X
X/* Return f, 'rounded down' to a word begin */
X
Xstatic int
Xtewordbegin(tp, f)
X	TEXTEDIT *tp;
X	int f;
X{
X	f= zaddgap(f);
X	for (;;) {
X		if (f == 0 || isspace(zcharbefore(f)))
X			break;
X		zdecr(&f);
X	}
X	return zsubgap(f);
X}
X
X/* Ditto to word end */
X
Xstatic int
Xtewordend(tp, f)
X	TEXTEDIT *tp;
X	int f;
X{
X	f= zaddgap(f);
X	for (;;) {
X		if (f >= tp->buflen || isspace(zcharat(f)))
X			break;
X		zincr(&f);
X	}
X	return zsubgap(f);
X}
X
Xint
Xtegetleft(tp)
X	TEXTEDIT *tp;
X{
X	return tp->left;
X}
X
Xint
Xtegettop(tp)
X	TEXTEDIT *tp;
X{
X	return tp->top;
X}
X
Xint
Xtegetright(tp)
X	TEXTEDIT *tp;
X{
X	return tp->right;
X}
X
Xint
Xtegetbottom(tp)
X	TEXTEDIT *tp;
X{
X	return tp->bottom;
X}
X
Xvoid
Xtemove(tp, left, top, width)
X	TEXTEDIT *tp;
X	coord left, top, width;
X{
X	temovenew(tp, left, top, left+width, top + tp->nlines*tp->vspace);
X}
X
X/*ARGSUSED*/
Xvoid
Xtemovenew(tp, left, top, right, bottom)
X	TEXTEDIT *tp;
X	int left, top, right, bottom;
X{
X	int oldheight= tp->bottom - tp->top;
X	tp->left= left;
X	tp->top= top;
X	tp->right= right;
X	tp->bottom= tp->top + oldheight;
X	if (right - left != tp->width) {
X		tp->width= right - left;
X		tp->nlines= 0; /* Experimental! */
X		terecompute(tp, 0, tp->buflen);
X	}
X}
X
Xvoid
Xtesetfocus(tp, foc1, foc2)
X	TEXTEDIT *tp;
X	focpos foc1, foc2;
X{
X	if (foc1 > tp->buflen - tp->gaplen)
X		foc1= tp->buflen - tp->gaplen;
X	if (foc2 > tp->buflen - tp->gaplen)
X		foc2= tp->buflen - tp->gaplen;
X	if (foc1 < 0)
X		foc1= 0;
X	if (foc2 < foc1)
X		foc2= foc1;
X	techangefocus(tp, foc1, foc2);
X	tp->aim= UNDEF;
X	tp->focprev= FALSE;
X	tesetcaret(tp);
X}
X
Xint
Xtegetfoc1(tp)
X	TEXTEDIT *tp;
X{
X	return tp->foc;
X}
X
Xint
Xtegetfoc2(tp)
X	TEXTEDIT *tp;
X{
X	return tp->foc + tp->foclen;
X}
X
Xint
Xtegetnlines(tp)
X	TEXTEDIT *tp;
X{
X	return tp->nlines;
X}
X
Xchar *
Xtegettext(tp)
X	TEXTEDIT *tp;
X{
X	temovegapto(tp, tp->buflen - tp->gaplen);
X	if (tp->gaplen < 1)
X		tegrowgapby(tp, 1+RESERVE);
X	tp->buf[tp->gap]= EOS;
X	return tp->buf;
X}
X
Xint
Xtegetlen(tp)
X	TEXTEDIT *tp;
X{
X	return tp->buflen - tp->gaplen;
X}
X
Xvoid
Xtesetbuf(tp, buf, buflen)
X	TEXTEDIT *tp;
X	char *buf;
X	int buflen;
X{
X	bool drawing= tp->drawing;
X	
X	if (buf == NULL || buflen < 0)
X		return;
X	if (drawing)
X		wchange(tp->win, tp->left, tp->top, tp->right, tp->bottom);
X	free(tp->buf);
X	tp->buf= buf;
X	tp->buflen= buflen;
X	tp->foc= tp->foclen= tp->gap= tp->gaplen= 0;
X	tp->drawing= FALSE;
X	terecompute(tp, 0, tp->buflen);
X	if (drawing) {
X		tp->drawing= TRUE;
X		wchange(tp->win, tp->left, tp->top, tp->right, tp->bottom);
X	}
X}
X
X
X/* The following paragraph-drawing routines are experimental.
X   They cannibalize on the existing text-edit code,
X   which makes it trivial to ensure the lay-out is the same,
X   but causes overhead to initialize a text-edit struct.
X   The flag 'drawing' has been added to the textedit struct,
X   which suppresses calls to tesetcaret, wchange and wscroll
X   from tesetup and terecompute.
X   It doesn't suppress actual drawing, which only occurs when
X   tedraw is called.
X   Note -- this could be optimized, but it is infrequently,
X   so I don't care until I get complaints. */
X
X/* Draw a paragraph of text, exactly like tedraw would draw it.
X   Parameters are the top left corner, the width, the text and its length.
X   Return value is the v coordinate of the bottom line.
X   An empty string is drawn as one blank line. */
X
Xint
Xwdrawpar(left, top, text, width)
X	int left, top;
X	char *text;
X	int width;
X{
X	return _wdrawpar(left, top, text, width, TRUE);
X}
X
X/* Measure the height of a paragraph of text, when drawn with wdrawpar. */
X
Xint
Xwparheight(text, width)
X	char *text;
X	int width;
X{
X	return _wdrawpar(0, 0, text, width, FALSE);
X}
X
X/* Routine to do the dirty work for the above two.
X   Size calculations are implemented by going through the normal
X   routine but suppressing the actual drawing. */
X
Xstatic int
X_wdrawpar(left, top, text, width, draw)
X	int left, top;
X	char *text;
X	int width;
X	bool draw;
X{
X	TEXTEDIT *tp= tesetup((WINDOW*)NULL, left, top, left+width, top, FALSE);
X	int v;
X	
X	tesetbuf(tp, text, strlen(text));
X	if (draw)
X		tedraw(tp);
X	v= tegetbottom(tp);
X	tp->buf= NULL;
X	tefree(tp);
X	return v;
X}
END_OF_FILE
if test 14543 -ne `wc -c <'Packs/textedit/textedit.c'`; then
    echo shar: \"'Packs/textedit/textedit.c'\" unpacked with wrong size!
fi
# end of 'Packs/textedit/textedit.c'
fi
if test -f 'Ports/x11/dialog.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/x11/dialog.c'\"
else
echo shar: Extracting \"'Ports/x11/dialog.c'\" \(14224 characters\)
sed "s/^X//" >'Ports/x11/dialog.c' <<'END_OF_FILE'
X/* X11 STDWIN -- Dialog boxes */
X
X#include "x11.h"
X#include "llevent.h"
X
X/* The kinds of dialogs we know */
X
X#define MESSAGEKIND	0
X#define ASKYNCKIND	1
X#define ASKSTRKIND	2
X
X/* Display a message and wait until acknowledged */
X
Xvoid
Xwmessage(prompt)
X	char *prompt;
X{
X	(void) dialog(prompt, (char*)NULL, 0, MESSAGEKIND, 0);
X}
X
X/* Ask a yes/no question.
X   Return value: yes ==> 1, no ==> 0, cancel (^C) ==> -1.
X   Only the first non-blank character of the string typed is checked.
X   The 'def' parameter is returned when an empty string is typed. */
X
Xint
Xwaskync(prompt, def)
X	char *prompt;
X	int def;
X{
X	return dialog(prompt, (char*)NULL, 0, ASKYNCKIND, def);
X}
X
X/* Ask for a string. */
X
Xbool
Xwaskstr(prompt, buf, len)
X	char *prompt;
X	char *buf;
X	int len;
X{
X	return dialog(prompt, buf, len, ASKSTRKIND, TRUE);
X}
X
X/* Definition for the current dialog box */
X
Xstatic struct windata box;	/* Window descriptor for the dialog box */
Xstatic unsigned long fg, bg;	/* Foreground, background pixel values */
Xstatic GC b_gc;			/* Corresponding Graphics Context */
X
X/* Definition for a command "button" or text item in a dialog box */
X
Xstruct button {
X	char type;		/* Button, label or text */
X	char *text;		/* The button label */
X	int ret;		/* Value to return when chosen */
X	struct windata wd;	/* Window description */
X	tbool down;		/* Button is pressed */
X	tbool inside;		/* Mouse inside button */
X	tbool hilite;		/* Button is hilited */
X	tbool def;		/* Set if default button */
X};
X
X/* Constants used in button definition 'type' field above */
X
X#define LABEL	'l'
X#define TEXT	't'
X#define BUTTON	'b'
X
Xstatic int nbuttons;		/* number of buttons and items */
Xstatic struct button *buttonlist; /* Definition list */
X
X/* Constants guiding button dimensions */
X
Xstatic int charwidth, textheight;
Xstatic int promptwidth;
Xstatic int buttonwidth;
X
X/* Dialog routine.
X   Create the window and subwindows, then engage in interaction.
X   Return the proper return value for waskync or waskstr.
X*/
X
X/* Dimension of buttons:
X   vertically:
X   	- 1 pixel white space around text,
X   	- 1 pixel wide border,
X   	- q pixel white space around border
X   horizontally:
X   	- 1 space character around text
X   	- 1 pixel wide border
X   	- 1 pixel white space around border
X   The prompt and reply are placed as buttons but their
X   border is white.
X   For a message, the OK button is to the right of the text,
X   separated from the prompt by two extra space characters.
X*/
X
Xstatic int
Xdialog(prompt, buf, len, kind, def)
X	char *prompt;		/* Prompt string */
X	char *buf;		/* Reply buffer, or NULL if unused */
X	int len;		/* Size of reply buffer */
X	int kind;		/* Dialog kind */
X	int def;		/* Default return value */
X{
X	WINDOW *act;
X	XFontStruct *save_wf= _wf;
X	int ret;
X	int textlen= 60;
X	
X	_wf= _wmf; /* So we can use wtextwidth() etc. */
X	
X	/* Compute various useful dimensions */
X	charwidth= wcharwidth(' ');
X	textheight= wlineheight();
X	promptwidth= wtextwidth(prompt, -1);
X	if (kind == MESSAGEKIND)
X		buttonwidth= wtextwidth("OK", 2);
X	else
X		buttonwidth= wtextwidth("Cancel", 6);
X	
X	/* Compute the outer box dimensions */
X	switch (kind) {
X	case MESSAGEKIND:
X		box.width= promptwidth + buttonwidth + 6*charwidth + 8;
X		box.height= textheight + 6;
X		break;
X	case ASKYNCKIND:
X		box.width= promptwidth + 2*charwidth + 4;
X		CLIPMIN(box.width, 3*(buttonwidth + 2*charwidth + 4));
X		box.height= 2 * (textheight + 6);
X		break;
X	default:
X		_wdebug(0, "dialog: bad kind");
X		kind= ASKSTRKIND;
X		/* Fall through */
X	case ASKSTRKIND:
X		box.width= promptwidth + 2*charwidth + 4;
X		CLIPMAX(textlen, len);
X		CLIPMIN(box.width, textlen*charwidth);
X		CLIPMIN(box.width, 2*(buttonwidth + 2*charwidth + 4));
X		box.height= 3 * (textheight + 6);
X		break;
X	}
X	CLIPMAX(box.width, WidthOfScreen(_ws));
X	CLIPMAX(box.height, HeightOfScreen(_ws));
X	
X	/* Compute the box position:
X	   above a window if possible,
X	   on the screen if necessary. */
X	
X	/* XXX Default placement could use an option resource */
X	
X	act= _w_get_last_active();
X	if (act != NULL) {
X		Window child_dummy;
X		if (!XTranslateCoordinates(_wd, act->wi.wid,
X			RootWindowOfScreen(_ws),
X#ifdef CENTERED
X			(act->wi.width - box.width) / 2,
X			(act->wi.height - box.height) / 2,
X#else
X			0,
X			0,
X#endif
X			&box.x, &box.y, &child_dummy))
X			act= NULL; /* Couldn't do it -- center on screen */
X	}
X	if (act == NULL) {
X		/* No window to cover */
X#ifdef CENTERED
X		/* center the box in the screen */
X		box.x= (WidthOfScreen(_ws) - box.width) / 2;
X		box.y= (HeightOfScreen(_ws) - box.height) / 2;
X#else
X		/* use top left screen corner */
X		box.x= box.y = 2*IBORDER + 1;
X		/* well, 1 pixel from the corner, to fool twm */
X#endif
X	}
X	
X	/* Clip the box to the screen */
X	
X	CLIPMAX(box.x, WidthOfScreen(_ws) - box.width);
X	CLIPMAX(box.y, HeightOfScreen(_ws) - box.height);
X	CLIPMIN(box.x, 0);
X	CLIPMIN(box.y, 0);
X	_wdebug(1, "dialog box: x=%d y=%d w=%d h=%d",
X		box.x, box.y, box.width, box.height);
X	
X	/* Create the box window and its GC */
X	
X	fg= _wgetpixel("menuForeground", "Foreground",
X						BlackPixelOfScreen(_ws));
X	bg= _wgetpixel("menuBackground", "Background",
X						WhitePixelOfScreen(_ws));
X	box.border= 2*IBORDER;
X	(void) _wcreate(&box, RootWindowOfScreen(_ws), 0, FALSE, fg, bg);
X	_wsaveunder(&box, True);
X	XSelectInput(_wd, box.wid,
X		ExposureMask|KeyPressMask|StructureNotifyMask);
X	b_gc= _wgcreate(box.wid, _wf->fid, fg, bg);
X	
X	/* Keep window managers happy:
X	   a name for WM's that insist on displaying a window title;
X	   class hints;
X	   WM hints;
X	   size hints to avoid interactive window placement;
X	   and "transient hints" to link it to an existing window. 
X	   The latter two only if the dialog box belongs to a window. */
X	
X	/* XXX This code could be unified with similar code in windows.c */
X	
X	/* The name is taken from _wprogname, to make it clear what
X	   application a dialog belongs to (especially if there is
X	   no window for it yet). */
X	
X	XStoreName(_wd, box.wid, _wprogname);
X	
X	/* Set class hints */
X	{
X		XClassHint classhint;
X		classhint.res_name= _wprogname;
X		classhint.res_class= "StdwinDialog";
X		XSetClassHint(_wd, box.wid, &classhint);
X	}
X	
X	/* Set WM hints */
X	{
X		XWMHints wmhints;
X		wmhints.flags = InputHint | StateHint;
X		wmhints.input = 1;
X		wmhints.initial_state = NormalState;
X		XSetWMHints(_wd, box.wid, &wmhints);
X	}
X	
X	if (act != NULL) {
X		XSizeHints sizehints;
X		
X		/* Pretend the user specified the size and position,
X		   in an attempt to avoid window manager interference */
X		sizehints.x= box.x - box.border;
X		sizehints.y= box.y - box.border;
X		sizehints.width= box.width;
X		sizehints.height= box.height;
X		sizehints.flags= USPosition|USSize;
X		XSetNormalHints(_wd, box.wid, &sizehints);
X		
X		XSetTransientForHint(_wd, box.wid, act->wo.wid);
X	}
X	
X	/* Create the prompt label */
X	
X	addbutton(LABEL, prompt, def, FALSE,
X		2,
X		2,
X		promptwidth + 2*charwidth,
X		textheight + 2);
X	
X	/* Create the command buttons and text field (for ASKSTRKIND).
X	   Note that our x, y convention differs from XCreateWindow:
X	   we don't include the border width. */
X	
X	switch (kind) {
X	case MESSAGEKIND:
X		addbutton(BUTTON, "OK", def, FALSE,
X			box.width - buttonwidth - 2*charwidth - 2, 2,
X			buttonwidth + 2*charwidth,
X			textheight + 2);
X		break;
X	case ASKYNCKIND:
X		addbutton(BUTTON, "Yes", 1, def==1,
X			2,
X			box.height - textheight - 4,
X			buttonwidth + 2*charwidth,
X			textheight + 2);
X		addbutton(BUTTON, "No", 0, def==0,
X			buttonwidth + 2*charwidth + 6,
X			box.height - textheight - 4,
X			buttonwidth + 2*charwidth,
X			textheight + 2);
X		addbutton(BUTTON, "Cancel", -1, def==-1,
X			box.width - buttonwidth - 2*charwidth - 2,
X			box.height - textheight - 4,
X			buttonwidth + 2*charwidth,
X			textheight + 2);
X		break;
X	case ASKSTRKIND:
X		addbutton(BUTTON, "OK", 1, FALSE,
X			2,
X			box.height - textheight - 4,
X			buttonwidth + 2*charwidth,
X			textheight + 2);
X		addbutton(BUTTON, "Cancel", 0, FALSE,
X			box.width - buttonwidth - 2*charwidth - 2,
X			box.height - textheight - 4,
X			buttonwidth + 2*charwidth,
X			textheight + 2);
X		addbutton(TEXT, buf, def, FALSE,
X			2,
X			textheight + 8,
X			box.width - 4,
X			textheight + 2);
X		break;
X	}
X	
X	/* Finish the work.
X	   Map the window, process events, extract text,
X	   destroy everything, return value. */
X	
X	XMapRaised(_wd, box.wid);
X	
X	ret=dialogeventloop(def);
X	if (kind == ASKSTRKIND && ret < 0)
X		ret= 0;
X	
X	if (ret > 0 && len > 0)
X		gettext(buf, len);
X	
X	XFreeGC(_wd, b_gc);
X	killbuttons();
X	XDestroyWindow(_wd, box.wid);
X	XFlush(_wd);
X	
X	_wf= save_wf;
X	
X	return ret;
X}
X
X/* Add a command button */
X
Xstatic
Xaddbutton(type, text, ret, def, x, y, width, height)
X	int type;
X	char *text;
X	int ret;
X	bool def;
X	int x, y, width, height;
X{
X	struct button b;
X	int cursor= (type == BUTTON) ? XC_arrow : 0;
X	
X	b.type= type;
X	b.text= strdup(text);
X	b.ret= ret;
X	b.def= def;
X	
X	b.wd.x= x;
X	b.wd.y= y;
X	b.wd.width= width;
X	b.wd.height= height;
X	
X	if (type == LABEL)
X		b.wd.border= 0;
X	else
X		b.wd.border= IBORDER;
X	(void) _wcreate(&b.wd, box.wid, cursor, TRUE, fg, bg);
X	XSelectInput(_wd, b.wd.wid,
X		type == BUTTON ?
X			ExposureMask|ButtonPressMask|ButtonReleaseMask|
X			EnterWindowMask|LeaveWindowMask
X		:	ExposureMask);
X	
X	b.down= 0;
X	b.inside= FALSE;
X	b.hilite= type == TEXT && text[0] != EOS;
X	
X	L_APPEND(nbuttons, buttonlist, struct button, b);
X}
X
X/* Dialog event processing loop.
X   Return number of button selected, -1 for Return, -2 for ^C. */
X
Xstatic struct button *whichbutton(); /* Forward */
X
Xstatic int
Xdialogeventloop(def)
X	int def;
X{
X	for (;;) {
X		XEvent e;
X		struct button *bp;
X		int c;
X		
X		XNextEvent(_wd, &e);
X		_wdebug(3, "dlog2: evt type %d", e.type);
X		bp= whichbutton(e.xbutton.window);
X		if (bp != NULL) {
X			if (buttonevent(bp, &e)) {
X				return bp->ret;
X			}
X		}
X		else if (e.xbutton.window == box.wid || e.type == KeyPress) {
X			switch (e.type) {
X			
X			case KeyPress:
X				switch (c= charcode(&e.xkey)) {
X				case EOS:
X					break;
X				case '\003': /* ^C, interrupt */
X					return -1;
X					/* Fall through */
X				case '\n':
X				case '\r':
X					return def;
X				default:
X					if (!addchar(c))
X						XBell(_wd, 0);
X					break;
X				}
X				break;
X			
X			case MapNotify:
X				/* Could set the input focus if another
X				   of our windows has it */
X				break;
X			
X			default:
X				_wdebug(3, "dialog: box ev %d", e.type);
X				if (e.type == ButtonPress)
X					XBell(_wd, 0);
X				break;
X			
X			}
X		}
X		else {
X			switch (e.type) {
X			case ButtonPress:
X			case KeyPress:
X				_wdebug(3, "dialog: alien press %d", e.type);
X				XBell(_wd, 0);
X				break;
X			case ButtonRelease:
X			case MotionNotify:
X				_wdebug(3, "dialog: alien move %d", e.type);
X				break;
X			default:
X				_wdebug(3, "dialog: alien llev %d", e.type);
X				_w_ll_event(&e);
X				break;
X			}
X		}
X	}
X}
X
X/* Find out which button a given Window ID belongs to (if any) */
X
Xstatic struct button *
Xwhichbutton(w)
X	Window w;
X{
X	int i;
X	
X	for (i= nbuttons; --i >= 0; ) {
X		if (w == buttonlist[i].wd.wid)
X			return &buttonlist[i];
X	}
X	return NULL;
X}
X
X/* Return the character code corresponding to a key event.
X   Returns EOS if no ASCII character. */
X
Xstatic int
Xcharcode(kep)
X	XKeyEvent *kep;
X{
X	KeySym keysym;
X	char strbuf[10];
X	
X	if (XLookupString(kep, strbuf, sizeof strbuf,
X		&keysym, (XComposeStatus*)NULL) <= 0)
X		return EOS;
X	else
X		return strbuf[0];
X}
X
X/* Append a character to the text item.
X   Here it is that we assume that the text item is last.
X   Unfortunately we can't use textedit (yet) to support all
X   desirable functionality, but we do support backspace
X   and overwriting the entire text. */
X
Xstatic bool
Xaddchar(c)
X	int c;
X{
X	struct button *bp= &buttonlist[nbuttons - 1];
X	int i;
X	
X	if (bp->type != TEXT || bp->text == NULL)
X		return FALSE;
X	i= strlen(bp->text);
X	if (c == '\b' || c == '\177' /*DEL*/ ) {
X		if (i > 0) {
X			bp->text[i-1]= EOS;
X			bp->hilite= FALSE;
X		}
X	}
X	else {
X		if (bp->hilite) {
X			i= 0;
X			bp->hilite= FALSE;
X		}
X		bp->text= realloc(bp->text, (unsigned)(i+2));
X		if (bp->text != NULL) {
X			bp->text[i]= c;
X			bp->text[i+1]= EOS;
X		}
X	}
X	drawbutton(bp);
X	return TRUE;
X}
X
X/* Process an event directed to a given button.
X   This also updates the highlighting. */
X
Xstatic bool
Xbuttonevent(bp, xep)
X	struct button *bp;
X	XEvent *xep;
X{
X	bool hit= FALSE;
X	
X	switch (xep->type) {
X	
X	case Expose:
X		drawbutton(bp);
X		return FALSE;
X	
X	case ButtonPress:
X		if (bp->down == 0)
X			bp->down= xep->xbutton.button;
X		break;
X	
X	case ButtonRelease:
X		if (bp->down == xep->xbutton.button) {
X			hit= bp->inside;
X			bp->down= 0;
X		}
X		break;
X	
X	case EnterNotify:
X		bp->inside= TRUE;
X		break;
X	
X	case LeaveNotify:
X		bp->inside= FALSE;
X		break;
X	
X	default:
X		return FALSE;
X	
X	}
X	hilitebutton(bp, bp->down > 0 && bp->inside);
X	return hit;
X}
X
X/* Draw procedure to draw a command button or text item */
X
Xstatic
Xdrawbutton(bp)
X	struct button *bp;
X{
X	char *text= bp->text == NULL ? "" : bp->text;
X	int len= strlen(text);
X	int width= XTextWidth(_wmf, text, len);
X	int x= (bp->type == BUTTON) ? (bp->wd.width - width) / 2 : charwidth;
X	int y= (bp->wd.height + _wmf->ascent - _wmf->descent) / 2;
X	
X	XClearWindow(_wd, bp->wd.wid);
X	XDrawString(_wd, bp->wd.wid, b_gc, x, y, text, len);
X	/* Indicate the default button with an underline */
X	if (bp->def) {
X		unsigned long ulpos, ulthick;
X		if (!XGetFontProperty(_wmf, XA_UNDERLINE_POSITION, &ulpos))
X			ulpos= _wmf->descent/2;
X		if (!XGetFontProperty(_wmf, XA_UNDERLINE_THICKNESS,&ulthick)) {
X			ulthick= _wmf->descent/3;
X			CLIPMIN(ulthick, 1);
X		}
X		_winvert(bp->wd.wid, b_gc,
X			x, (int)(y + ulpos), width, (int)ulthick);
X	}
X	if (bp->hilite)
X		_winvert(bp->wd.wid, b_gc,
X			0, 0, bp->wd.width, bp->wd.height);
X}
X
X/* Highlight or unhighlight a command button */
X
Xstatic
Xhilitebutton(bp, hilite)
X	struct button *bp;
X	bool hilite;
X{
X	if (bp->hilite != hilite) {
X		_winvert(bp->wd.wid, b_gc,
X			0, 0, bp->wd.width, bp->wd.height);
X		bp->hilite= hilite;
X	}
X}
X
X/* Extract the text from the text item */
X
Xstatic
Xgettext(buf, len)
X	char *buf;
X	int len;
X{
X	struct button *bp= &buttonlist[nbuttons - 1];
X	
X	if (bp->type != TEXT || bp->text == NULL)
X		return;
X	strncpy(buf, bp->text, len-1);
X	buf[len-1]= EOS;
X}
X
X/* Destroy all buttons and associated data structures */
X
Xstatic
Xkillbuttons()
X{
X	int i;
X	for (i= 0; i < nbuttons; ++i)
X		free(buttonlist[i].text);
X	L_SETSIZE(nbuttons, buttonlist, struct button, 0);
X}
END_OF_FILE
if test 14224 -ne `wc -c <'Ports/x11/dialog.c'`; then
    echo shar: \"'Ports/x11/dialog.c'\" unpacked with wrong size!
fi
# end of 'Ports/x11/dialog.c'
fi
echo shar: End of archive 6 \(of 19\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 19 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