STDWIN 0.9.5, Part 08/19

Guido van Rossum guido at cwi.nl
Mon Mar 4 21:57:58 AEST 1991


Archive-name: stdwin/part08

#! /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 8 (of 19)."
# Contents:  Appls/dpv/dpvfonts.c Doc/seldoc.ms
#   Packs/textedit/textlow.c Ports/mac/event.c Ports/mac/menu.h
# Wrapped by guido at voorn.cwi.nl on Mon Mar  4 12:37:27 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Appls/dpv/dpvfonts.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Appls/dpv/dpvfonts.c'\"
else
echo shar: Extracting \"'Appls/dpv/dpvfonts.c'\" \(12151 characters\)
sed "s/^X//" >'Appls/dpv/dpvfonts.c' <<'END_OF_FILE'
X/* dpv -- ditroff previewer.  Font translation. */
X
X#include "dpv.h"
X#include "dpvmachine.h"
X#include "dpvoutput.h"
X
X/* Font translation table, to map ditroff font names to font names
X   STDWIN (really the underlying window system) understands.
X   This information should really be read from a configuration file.
X   For now, we know to map some ditroff names for Harris and PostScript
X   fonts to more or less equivalent X11 and Mac fonts.
X   (The X fonts used are to be found in the Andrew distribution).
X   Because the current font scheme in STDWIN for X doesn't know about
X   wsetsize and wsetbold c.s., the translation process is different
X   for X than for the Macintosh. */
X
X#define NSIZES 10
X
X#define R	0
X#define B	1
X#define I	2
X#define BI	3
X
Xstatic struct _translate {
X	char *harname;
X	char *xname;
X	int style;
X	int sizes[NSIZES+1];
X} default_translate[]= {
X#ifdef macintosh
X	{"R",	"Times",	R},
X	{"I",	"Times",	I},
X	{"B",	"Times",	B},
X	{"BI",	"Times",	BI},
X	
X	{"H",	"Helvetica",	R},
X	{"HO",	"Helvetica",	I},
X	{"HB",	"Helvetica",	B},
X	{"HD",	"Helvetica",	BI},
X	
X	{"C",	"Courier",	R},
X	{"CO",	"Courier",	I},
X	{"CB",	"Courier",	B},
X	{"CD",	"Courier",	BI},
X	
X	{"lp",	"Courier",	R},
X	
X	{"Vl",	"Helvetica",	R},
X	{"vl",	"Helvetica",	R},
X	{"V",	"Helvetica",	R},
X	{"v",	"Helvetica",	R},
X	
X	/* Font used by funny character translation */
X	
X	{"Symbol", "Symbol",	R},
X#else
X#ifdef X11R2
X	/* X11 Release 2, using fonts from Andrew */
X	
X	/* PostScript font names */
X	
X	{"R",	"times%d",	R, 8, 10, 12, 16, 22, 0},
X	{"I",	"times%di",	R, 8, 10, 12, 16, 22, 0},
X	{"B",	"times%db",	R, 8, 10, 12, 16, 22, 0},
X	{"BI",	"times%dbi",	R, 8, 10, 12, 16, 22, 0},
X	
X	{"H",	"helvetica%d",	R, 8, 10, 12, 16, 22, 0},
X	{"HO",	"helvetica%di",	R, 8, 10, 12, 16, 22, 0},
X	{"HB",	"helvetica%db",	R, 8, 10, 12, 16, 22, 0},
X	{"HD",	"helvetica%dbi",R, 8, 10, 12, 16, 22, 0},
X	
X	{"C",	"courier%df",	R, 8, 10, 12, 16, 22, 0},	
X	{"CO",	"courier%dif",	R, 8, 10, 12, 16, 22, 0},
X	{"CB",	"courier%dbf",	R, 8, 10, 12, 16, 22, 0},
X	{"CD",	"courier%dbif", R, 8, 10, 12, 16, 22, 0},
X	
X	/* CWI Harris font names (also R, I, B, BI) */
X	
X	/* Vega light, Vega, Vega medium (Helvetica look-alike) */
X	{"Vl",	"helvetica%d",	R, 8, 10, 12, 16, 22, 0},
X	{"vl",	"helvetica%di",	R, 8, 10, 12, 16, 22, 0},
X	{"V",	"helvetica%d",	R, 8, 10, 12, 16, 22, 0},
X	{"v",	"helvetica%di",	R, 8, 10, 12, 16, 22, 0},
X	{"Vm",	"helvetica%db",	R, 8, 10, 12, 16, 22, 0,},
X	{"vm",	"helvetica%dbi",R, 8, 10, 12, 16, 22, 0,},
X	
X	/* Baskerville (see also small caps) */
X	{"br",	"times%d",	R, 8, 10, 12, 16, 22, 0,},
X	{"bi",	"times%di",	R, 8, 10, 12, 16, 22, 0,},
X	{"bb",	"times%db",	R, 8, 10, 12, 16, 22, 0,},
X	{"bI",	"times%dbi",	R, 8, 10, 12, 16, 22, 0,},
X	
X	/* Century Schoolbook */
X	{"cr",	"times%d",	R, 8, 10, 12, 16, 22, 0,},
X	{"ci",	"times%di",	R, 8, 10, 12, 16, 22, 0,},
X	{"cb",	"times%db",	R, 8, 10, 12, 16, 22, 0,},
X	{"cI",	"times%dbi",	R, 8, 10, 12, 16, 22, 0,},
X	
X	/* Laurel */
X	{"lr",	"times%d",	R, 8, 10, 12, 16, 22, 0,},
X	{"li",	"times%di",	R, 8, 10, 12, 16, 22, 0,},
X	{"lb",	"times%db",	R, 8, 10, 12, 16, 22, 0,},
X	{"lI",	"times%dbi",	R, 8, 10, 12, 16, 22, 0,},
X	
X	/* Funny fonts mapped to Helvetica, at least they differ from Times */
X	{"G3",	"helvetica%d",	R, 8, 10, 12, 16, 22, 0,}, /* German no 3 */
X	{"fs",	"helvetica%d",	R, 8, 10, 12, 16, 22, 0,}, /* French Script */
X	{"RS",	"helvetica%di",	R, 8, 10, 12, 16, 22, 0,}, /* Rose Script */
X	{"SO",	"helvetica%db",	R, 8, 10, 12, 16, 22, 0,}, /* Scitype Open */
X	
X	/* OCR-B (line printer font) */
X	{"lp",	"courier%dbf",	R, 8, 10, 12, 0},
X	
X	/* Small caps fonts mapped to normal fonts */
X	{"Rs",	"times%d",	R, 8, 10, 12, 16, 22, 0,}, /* Times */
X	{"Bs",	"times%db",	R, 8, 10, 12, 16, 22, 0,}, /* Times bold */
X	{"bs",	"times%d",	R, 8, 10, 12, 16, 22, 0,}, /* Baskerville */
X	{"bS",	"times%db",	R, 8, 10, 12, 16, 22, 0,}, /* Baskerv. bold */
X	
X	/* Fonts used by funny character translation */
X	
X	{"symbol", "symbol%d",	R, 8, 10, 12, 16, 22, 0},
X	{"symbola","symbola%d", R, 8, 10, 12, 16, 22, 0},
X#else /* ! X11R3 */
X	/* X11 Release 3 fonts */
X	/* Also works for Release 4 */
X	
X	/* PostScript font names */
X	
X	{"R",	"-*-times-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"I",	"-*-times-medium-i-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"B",	"-*-times-bold-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"BI",	"-*-times-bold-i-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	
X	{"H",	"-*-helvetica-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"HO",	"-*-helvetica-medium-o-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"HB",	"-*-helvetica-bold-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"HD",	"-*-helvetica-bold-o-*--%d-*",R, 8, 10, 12, 14, 18, 24, 0},
X	
X	{"C",	"-*-courier-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},	
X	{"CO",	"-*-courier-medium-o-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"CB",	"-*-courier-bold-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"CD",	"-*-courier-bold-o-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	
X	/* CW is a common alias for C */
X	{"CW",	"-*-courier-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},	
X	
X	/* CWI Harris font names (also R, I, B, BI) */
X	
X	/* Vega light, Vega, Vega medium (Helvetica look-alike) */
X	{"Vl",	"-*-helvetica-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"vl",	"-*-helvetica-medium-o-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"V",	"-*-helvetica-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"v",	"-*-helvetica-medium-o-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X	{"Vm",	"-*-helvetica-bold-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	{"vm",	"-*-helvetica-bold-o-*--%d-*",R, 8, 10, 12, 14, 18, 24, 0,},
X	
X	/* Baskerville (see also small caps) */
X	{"br",	"-*-times-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	{"bi",	"-*-times-medium-i-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	{"bb",	"-*-times-bold-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	{"bI",	"-*-times-bold-i-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	
X	/* Century Schoolbook */
X	{"cr",	"-*-new century schoolbook-medium-r-*--%d-*",
X	R, 8, 10, 12, 14, 18, 24, 0,},
X	{"ci",	"-*-new century schoolbook-medium-i-*--%d-*",
X	R, 8, 10, 12, 14, 18, 24, 0,},
X	{"cb",	"-*-new century schoolbook-bold-r-*--%d-*",
X	R, 8, 10, 12, 14, 18, 24, 0,},
X	{"cI",	"-*-new century schoolbook-bold-i-*--%d-*",
X	R, 8, 10, 12, 14, 18, 24, 0,},
X	
X	/* Laurel */
X	{"lr",	"-*-times-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	{"li",	"-*-times-medium-i-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	{"lb",	"-*-times-bold-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	{"lI",	"-*-times-bold-i-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	
X	/* Funny fonts mapped to Helvetica, at least they differ from Times */
X	{"G3",	"-*-helvetica-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	/* German no 3 */
X	{"fs",	"-*-helvetica-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	/* French Script */
X	{"RS",	"-*-helvetica-medium-o-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	/* Rose Script */
X	{"SO",	"-*-helvetica-bold-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	/* Scitype Open */
X	
X	/* OCR-B (line printer font) */
X	{"lp",	"-*-courier-bold-r-*--%d-*", R, 8, 10, 12, 0},
X	
X	/* Small caps fonts mapped to normal fonts */
X	{"Rs",	"-*-times-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	/* Times */
X	{"Bs",	"-*-times-bold-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	/* Times bold */
X	{"bs",	"-*-times-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	/* Baskerville */
X	{"bS",	"-*-times-bold-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0,},
X	/* Baskerville bold */
X	
X	/* Fonts used by funny character translation */
X	
X	{"r3symbol", "*-*-symbol-medium-r-*--%d-*", R, 8, 10, 12, 14, 18, 24, 0},
X#endif /* ! X11R2 */
X#endif /* ! macintosh */
X	
X	{NULL,	NULL}
X};
X
Xstatic struct _translate *translate = default_translate;
X
X/* Tell STDWIN to use the desired font and size.
X   Call at start of page and after each font or size change. */
X
Xusefont()
X{
X	char *fontname;
X	
X	if (showpage != ipage)
X		return;
X	
X	fontname= fonts.name[font];
X	if (fontname != NULL)
X		fonthack(fontname);
X	/* Else, font not loaded -- assume in initialization phase */
X	baseline= wbaseline();
X	lineheight= wlineheight();
X	recheck();
X}
X
Xfonthack(fontname)
X	char *fontname;
X{
X	int i;
X	int havesize;
X	char *harname;
X	char buf[256];
X	struct _translate *t;
X	
X	for (t= translate; t->harname != NULL; ++t) {
X		if (strcmp(t->harname, fontname) == 0)
X			break;
X	}
X	if (t->harname == NULL) {
X		fontwarning(fontname);
X	}
X	else {
X#ifdef macintosh
X		wsetfont(t->xname);
X		wsetsize(size);
X		wsetplain();
X		switch (t->style) {
X		case I: wsetitalic(); break;
X		case B: wsetbold(); break;
X		case BI: wsetbolditalic(); break;
X		}
X#else
X		havesize= size;
X		for (i= 0; ; ++i) {
X			if (t->sizes[i] >= havesize || t->sizes[i+1] == 0) {
X				havesize= t->sizes[i];
X				break;
X			}
X		}
X		sprintf(buf, t->xname, havesize);
X		wsetfont(buf);
X#endif
X	}
X}
X
X/* Issue a warning.
X   Avoid warning many times in a row about the same font. */
X
Xfontwarning(fontname)
X	char *fontname;
X{
X	static char lastwarning[200];
X	char buf[256];
X	
X	if (strncmp(lastwarning, fontname, sizeof lastwarning) != 0) {
X		strncpy(lastwarning, fontname, sizeof lastwarning);
X		sprintf(buf, "mapping for font %s unknown", fontname);
X		error(WARNING, buf);
X	}
X}
X
X/* Get a token */
X
Xstatic char *
Xgettok(pp)
X	char **pp;
X{
X	char *p = *pp;
X	char *start;
X	char c;
X	
X	while (isspace(c = *p++)) /* Skip to start of token */
X		;
X	if (c == '\0' || c == '\n' || c == '#') {
X		if (dbg > 2)
X			if (c == '#')
X				fprintf(stderr, "next token is comment\n");
X			else if (c == '\n')
X				fprintf(stderr, "next token is newline\n");
X			else
X				fprintf(stderr, "next token is EOS\n");
X		return NULL; /* End of line of comment */
X	}
X	start = p-1; /* Remember start of token */
X	while (!isspace(c = *p++) && c != '\0') /* Skip to end of token */
X		;
X	if (c == '\0')
X		p--;
X	else
X		p[-1] = '\0'; /* Zero-terminate token */
X	*pp = p; /* Start point for next token */
X	if (dbg > 2)
X		fprintf(stderr, "next token: %s\n", start);
X	return start;
X}
X
Xstatic void
Xaddtrans(pnt, pt, harname, xname, style, sizes)
X	int *pnt;
X	struct _translate **pt;
X	char *harname;
X	char *xname;
X	int style;
X	int sizes[];
X{
X	int i = (*pnt)++;
X	struct _translate *t = *pt;
X	
X	if (i == 0)
X		t = (struct _translate *) malloc(sizeof(struct _translate));
X	else
X		t = (struct _translate *)
X			realloc((char *)t, sizeof(struct _translate) * *pnt);
X	if (t == NULL)
X		error(FATAL, "not enough memory for font translations");
X	*pt = t;
X	t += i;
X	t->harname = strdup(harname);
X	t->xname = strdup(xname);
X	t->style = style;
X	for (i = 0; i <= NSIZES; i++)
X		t->sizes[i] = sizes[i];
X}
X
X/* Read a file of alternative font translations. */
X
Xreadtrans(filename)
X	char *filename;
X{
X	struct _translate *t;
X	int nt;
X	FILE *fp;
X	int line;
X	char buf[1000];
X	char *p;
X	char *harname;
X	char *xname;
X	char *sizetemp;
X	int sizes[NSIZES+1];
X	static int defsizes[NSIZES+1] = {8, 10, 12, 14, 18, 24, 0};
X	int nsizes;
X	
X	fp = fopen(filename, "r");
X	if (fp == NULL)
X		error(FATAL, "can't find font translations file %s", filename);
X	if (dbg > 0)
X		fprintf(stderr, "reading translations from %s\n", filename);
X	t = NULL;
X	nt = 0;
X	line = 0;
X	while (fgets(buf, sizeof buf, fp) != NULL) {
X		line++;
X		if (dbg > 1)
X			fprintf(stderr, "line %d: %s\n", line, buf);
X		p = buf;
X		harname = gettok(&p);
X		if (harname == NULL)
X			continue; /* Blank line or comment */
X		xname = gettok(&p);
X		if (xname == NULL) {
X			error(WARNING, "%s(%d): incomplete line (only '%s')",
X						filename, line, harname);
X			continue;
X		}
X		/* Style is always R */
X		nsizes = 0;
X		while (nsizes < NSIZES && (sizetemp = gettok(&p)) != NULL) {
X			sizes[nsizes] = atoi(sizetemp);
X			if (sizes[nsizes] <= 0 ||
X					nsizes > 0 &&
X					sizes[nsizes] <= sizes[nsizes-1]) {
X				error(WARNING,
X				    "%s(%d): bad or non-increasing size '%s'",
X				    filename, line, sizetemp);
X			}
X			else
X				nsizes++;
X		}
X		if (nsizes > 0)
X			while (nsizes <= NSIZES)
X				sizes[nsizes++] = 0;
X		addtrans(&nt, &t, harname, xname, R,
X			nsizes == 0 ? defsizes : sizes);
X	}
X	if (dbg > 0)
X		fprintf(stderr, "done reading translations.\n");
X	fclose(fp);
X	if (nt == 0)
X		error(FATAL, "%s: no valid font translations", filename);
X	addtrans(&nt, &t, (char *)NULL, (char *)NULL, R, defsizes);
X	translate = t;
X}
END_OF_FILE
if test 12151 -ne `wc -c <'Appls/dpv/dpvfonts.c'`; then
    echo shar: \"'Appls/dpv/dpvfonts.c'\" unpacked with wrong size!
fi
# end of 'Appls/dpv/dpvfonts.c'
fi
if test -f 'Doc/seldoc.ms' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Doc/seldoc.ms'\"
else
echo shar: Extracting \"'Doc/seldoc.ms'\" \(12081 characters\)
sed "s/^X//" >'Doc/seldoc.ms' <<'END_OF_FILE'
X.\" To format, use (di)troff -ms; and make sure macros.ms is around!
X.so macros.ms
X.SH
XUsing X11 Selections and Cut Buffers in STDWIN
X.LP
XThe C STDWIN interface has been extended to support the
X.I selection
Xmechanism used by X11.
XSupport for the ring of 8 cut buffers is also provided.
X.PP
XThis document assumes you are familiar with STDWIN as a programmer and
Xwith X11 as an end user (at least xterm experience and some idea of the
Xclient-server model).
X.NH
XWhat are Selections?
X.LP
XX11 supports an arbitrary number of selections, but version 1.0 of the
XICCCM (Inter-Client Communication Conventions Manual, by David Rosenthal)
Xrequires only that clients support three selections called PRIMARY,
XSECONDARY and CLIPBOARD.
XI will further reference these in lower case.
X.PP
XThe
X.I "primary selection"
Xis the mechanism you normally use to transfer data interactively
Xbetween clients (or within one client).
XIn xterm and text-oriented toolkit clients, you make a primary
Xselection by dragging with the left mouse button.
XThe contents of the selection are highlighted using inverse video.
XThe contents of the primary selection can be pasted into the same or
Xanother (toolkit) client by pressing the middle mouse button.
X.PP
XConventions for use of the
X.I "secondary selection"
Xare less well-known.
XIt is used as the second argument of operations with two arguments,
Xsuch as swap or replace operations.
XThere is no default support for it in the toolkit, but it is
Xpossible to customize toolkit clients to use it.
X.PP
XThe
X.I clipboard
Xis intended to hold data that the user has deleted and wants to insert
Xsomewhere later.
XIt is supported by the standard X11 client
X.I xclipboard ,
Xwhich displays the current contents of the clipboard.
XOther toolkit clients can be customized to use it.
X.NH
XSelections From the Client's Point of View
X.LP
XIt is important to realize that the contents of selections are
Xtransferred between clients at the time they are pasted; selections are
Xnot normally stored by the server.
XAt any time, a selection is ``owned'' by at most one client, the
X.I "selection owner" .
XDifferent selections may be owned by different clients.
XThe server keeps track of selection owners.
XWhen a client wants to become owner of a particular selection, it tells
Xthe server so, and the server will send the previous owner an event to
Xtell it that it no longer owns the selection.
X.PP
XThe protocol to transfer the contents of a selection between clients is
Xfairly involved.
XSomewhat simplified, it works as follows:
X.IP \(bu
XA client requests the contents of a selection from the server.
X.IP \(bu 2
XThe server sends the owner an event asking ``please give me this
Xselection.''
X.IP \(bu 2
XThe owner stores the contents of the selection as a
X.I property\(dg
X.FS
X\(dg
XA window
X.I property
Xis a named arbitrary piece of data associated with a window, stored by
Xthe server.
X.FE
Xon the requestor's window, and sends an event back (via the server)
Xtelling the requestor that the selection is stored.
X.IP \(bu 2
XThe requestor fetches the contents of the property, and deletes
Xthe property.
X.PP
XVarious complications are possible:
X.IP \(bu 2
XRace conditions: a client may be slow to respond to a mouse click, and
Xthe impatient user may have clicked again in another client's window.
XWhen the first client finally decides it wants to become selection
Xowner, the second client may already own it.
X.IP \(bu
XCrashes: a selection owner may crash before it has responded to a
Xrequest for the selection's contents.
X.IP \(bu
XSpace limitations on the server.
X.IP \(bu
XNegotiations about the type of the selection: a string could be stored
Xin simple ASCII or in a special format that retains font information,
Xand in fact a selection may contain a picture or an arbitrarily
Xcomplicated data structure that only a few clients know about.
X.NH
XThe STDWIN Interface to Selections
X.LP
XSTDWIN simplifies the concept of a selection somewhat and takes care of
Xmost details of communicating with other clients.
XIn STDWIN, selections are always ASCII strings and only the three
Xstandard selections are supported.
XThe strings are null-terminated but may also contain embedded null
Xcharacters, so a length is always provided.
X.PP
XThe header
X.cW <stdwin.h>
Xdefines constants that identify the selections:
X.cW WS_PRIMARY ,
X.cW WS_SECONDARY ,
Xand
X.cW WS_CLIPBOARD .
XThe application calls the function
X.cW wsetselection()
Xto become owner of a selection.
XIt may later receive an event of type
X.cW WE_LOST_SEL
Xtelling it that it lost ownership again.
XIt is also possible to voluntarily give up selection ownership by
Xcalling
X.cW wresetselection() .
XTo access the contents of a selection, whether you own it or not, call
Xthe function
X.cW wgetselection() .
XTransfer of selection contents to other clients is done automatically by
X.cW wgetevent()
Xand
X.cW wpollevent() .
XDetailed descriptions of the new functions follow:
X.NH 2
XFunction \*<wsetselection()\*>
X.LP
X.sC L
Xbool wsetselection(win, sel, data, len)
XWINDOW *win;
Xint sel;
Xchar *data;
Xint len;
X.eC
X.LP
XParameters:
X.IP \*<win\*> 6n
XSpecifies a window that will be associated with the selection.
XThis has no other meaning that limiting the lifetime of the selection to
Xthe lifetime of the window.
XIt will not be reported in
X.cW WE_LOST_SEL
Xevents.
X.IP \*<sel\*>
XSpecifies which selection should be set.
XIt should be one of the codes
X.cW WS_PRIMARY ,
X.cW WS_SECONDARY ,
Xor
X.cW WS_CLIPBOARD .
X.IP \*<data\*>
XSpecifies the data comprising the selection's contents.
XThis need not be null-terminated.
XIt is copied to a safe place by the function so it can be sent to
Xother clients later.
X.IP \*<len\*>
XSpecifies the length of the data, not including a terminating null byte.
X.LP
XThis function attempts to acquirpe ownership of the specified selection.
XThis may fail because of race conditions.
XThe function returns nonzero if it succeeds.
XIf it fails, the application should give the user visual feedback of the
Xfailure,
X.I e.g. ,
Xby not inverting the selected text.
X.NH 2
XFunction \*<wresetselection()\*>
X.LP
X.sC L
Xvoid wresetselection(sel)
Xint sel;
X.eC
X.LP
XParameters:
X.IP \*<sel\*> 6n
XSpecifies which selection should be reset.
XIt should be one of the codes
X.cW WS_PRIMARY ,
X.cW WS_SECONDARY ,
Xor
X.cW WS_CLIPBOARD .
X.LP
XIf the application owns the specified selection, this function cancels
Xownership.
XNo
X.cW WE_LOST_SEL
Xevents are generated for the selection.
X.NH 2
XFunction \*<wgetselection()\*>
X.LP
X.sC L
Xchar *wgetselection(sel, plen)
Xint sel;
Xint *plen;
X.eC
XParameters:
X.IP \*<sel\*> 6n
XSpecifies which selection should be retrieved.
XIt should be one of the codes
X.cW WS_PRIMARY ,
X.cW WS_SECONDARY ,
Xor
X.cW WS_CLIPBOARD .
X.IP \*<plen\*>
XInto this parameter, the length of the data is returned, excluding the
Xterminating null byte.
X.LP
XThis function retrieves the contents of the specified selection.
XIf it succeeds, a pointer to its data is returned.
XThe data is terminated by a null byte but may contain null bytes, so the
Xlength is returned separately.
XThe data pointer points to space internal to the STDWIN library.
XIt remains valid until the next call involving selections.
XIf the selection could not be retrieved somehow, a NULL pointer is
Xreturned.
XSelections longer that 32K may be truncated.
XSince the transfer mechanism requires the use of a window, a NULL
Xpointer is returned when the application currently has no windows open.
X.NH 2
XThe \*<WE_LOST_SEL\*> event type
X.LP
XA STDWIN application receives this event type when it owns a selection
X(a call to
X.cW wsetselection()
Xhas succeeded) and another client has become the new owner.
XThe
X.cW window
Xmember of the
X.cW EVENT
Xis set to
X.cW NULL .
XThe
X.cW u.sel
Xunion member is set to the code for the selection.
XThis event is not generated when selection ownership is given up by
Xcalling
X.cW wresetselection()
Xor by deleting its window.
X.NH
XThe STDWIN Interface to Cut Buffers
X.LP
XFor compatibility with old STDWIN or X11 clients and Andrew clients,
Xan interface to the cut buffer interface is also provided.
XThis is a ring of 8 buffers maintained at the server.
XThe following functions are available:
X.NH 2
XFunction \*<wsetcutbuffer()\*>
X.LP
X.sC L
Xvoid wsetcutbuffer(ibuffer, data, len)
Xint ibuffer;
Xchar *data;
Xint len;
X.eC
X.LP
XParameters:
X.IP \*<ibuffer\*> 10n
XSpecifies which buffer should be set, in the range [0 ... 7].
X.IP \*<data\*>
XSpecifies the data.
XIt need not be null-terminated.
X.IP \*<len\*>
XSpecifies the length of the data, excluding a terminating null byte.
X.LP
XThis function sets the contents of the specified cut buffer to the given
Xdata.
XNo indication of success or failure is given.
X.NH 2
XFunction \*<wgetcutbuffer()\*>
X.LP
X.sC L
Xchar *wgetcutbuffer(ibuffer, plen)
Xint ibuffer;
Xint *plen;
X.eC
X.LP
XParameters:
X.IP \*<ibuffer\*> 10n
XSpecifies which buffer should be retrieved, in the range [0 ... 7].
X.IP \*<plen\*>
XReturns the length of the data, excluding the terminating null byte.
X.LP
XThis function returns the contents of the specified cut buffer,
Xterminated by a null byte.
XIf the cut buffer is not accessible, it returns
X.cW NULL .
X.NH 2
XFunction \*<wrotatecutbuffers()\*>
X.LP
X.sC L
Xvoid wrotatecutbuffers(n)
Xint n;
X.eC
X.LP
XParameters:
X.IP \*<n\*> 4n
XSpecifies the amount of rotation.
XThis may be negative.
X.LP
XThe cut buffers are rotated as follows:
Xbuffer n gets the contents of buffer 0, buffer n+1 (mod 8) gets the
Xcontents of buffer 1, etc.
X.NH 2
XFunction \*<wsetclip()\*>
X.LP
X.sC L
Xvoid wsetclip(data, len)
Xchar *data;
Xint len;
X.eC
XThis function is equivalent to
X.sC
Xwsetcutbuffer(0, data, len);
Xwrotatecutbuffers(1);
X.eC
X.NH 2
XFunction \*<wgetclip()\*>
X.LP
X.sC L
Xchar *wgetclip()
X.eC
XThis function is equivalent to
X.sC
Xint len;
Xreturn wgetcutbuffer(0, &len);
X.eC
X(It throws away the length.)
X.NH
XSuggested Usage
X.LP
XTo conform to X11 conventions, STDWIN applications should normally use
Xthe primary selection, but use the cut buffers as a ``fall-back''
Xmechanism.
X.PP
XWhen the user has selected some text, the application should transfer
Xthe text to cut buffer 0 and rotate the buffers (the easiest way to do
Xthis is to call
X.cW wsetclip() ),
Xand then call
X.cW wsetselection()
Xto set the primary selection to the text.
XIf the latter call fails, the inverse video on the selected text should
Xbe removed.
XThe inverse video should also be removed when a
X.cW WE_LOST_SEL
Xevent is received.
XIf there is a text insertion point associated with the selection, it
Xshould be left at the position indicated by the last mouse click, or to
Xthe beginning of the selected text.
X.PP
XWhen the user desires to paste some text, the applcation should first
Xget the contents of the primary selection, and if this returns a NULL
Xpointer, it should get the contents of cut buffer 0.
XIf this returns a NULL pointer as well, the paste request should be
Xrefused (with a beep, or something similar).
X.PP
XThe conventions for selecting and pasting text are:
X.IP \(bu 2
XDragging with the left (first) mouse button is used to make a selection.
XDouble-clicking selects ``words.''
X.IP \(bu
XClicking with the middle mouse button requests a ``paste'' operation.
XIt does not move the insert point to the position of the click.
X.IP \(bu
XClicking with the right mouse button extends the selection at the end
Xclosest to the button click.
X.NH
XSelections and Macintosh STDWIN
X.LP
XThe Macintosh user interface standards prescribe only a single cut
Xbuffer, called the Clipboard.
XFor source compatibility with STDWIN applications developed for X11,
Xdummy versions of the selection functions are provided:
X.cW wsetselection()
Xand
X.cW wgetselection()
Xalways fail, and
X.cW wresetselection()
Xis ignored.
XVersions of the cut buffer functions are provided that identify cut
Xbuffer 0 with the Macintosh Clipboard and ignore the other cut buffers.
X.PP
XThe net effect is that STDWIN applications written for X11 selections
Xthat use the cut buffers as a fall-back mechanism will support the
XMacintosh Clipboard, albeit with an X11-like interface.
XMacintosh applications are encouraged to provide a standard Edit menu
Xwith the operations Cut, Copy and Paste and the standard shortcuts for
Xthem: Command-X, Command-C and Command-V.
END_OF_FILE
if test 12081 -ne `wc -c <'Doc/seldoc.ms'`; then
    echo shar: \"'Doc/seldoc.ms'\" unpacked with wrong size!
fi
# end of 'Doc/seldoc.ms'
fi
if test -f 'Packs/textedit/textlow.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Packs/textedit/textlow.c'\"
else
echo shar: Extracting \"'Packs/textedit/textlow.c'\" \(12558 characters\)
sed "s/^X//" >'Packs/textedit/textlow.c' <<'END_OF_FILE'
X/* Text Edit, low-level routines */
X
X/* CONVENTION:
X	routines beginning with te... have a first parameter 'tp';
X	routines beginning with z... don't, or are macros that
X	implicitly use a variable or parameter 'tp'
X*/
X
X#include "text.h"
X
X/* Variants on wtextwidth, wtextbreak, wdrawtext taking the gap in account.
X   These have two buffer offsets as parameters instead of a text pointer
X   and a length; tetextbreak also returns a buffer offset */
X
X/* These routines now also take tabs into account.
X   They should now only be called with a line start for 'pos' ! */
X
Xint
Xtetextwidth(tp, pos, end)
X	register TEXTEDIT *tp;
X	bufpos pos, end;
X{
X	char *p= tp->buf + pos;
X	register char *e= tp->buf +
X		(tp->gap >= pos && tp->gap < end ? tp->gap : end);
X	int w= 0;
X	register char *k;
X	
X	zcheckpos(pos);
X	zcheckpos(end);
X	zassert(pos <= end);
X	
X	/* This do loop is executed once or twice only! */
X	do {
X		for (k= p; k < e; ++k) {
X			if (*k == '\t') {
X				if (k > p)
X					w += wtextwidth(p, (int)(k-p));
X				w= znexttab(w);
X				p= k+1;
X			}
X		}
X		if (k > p)
X			w += wtextwidth(p, (int)(k-p));
X		if (tp->gap >= pos) {
X			p= tp->buf + zgapend;
X			e= tp->buf + end;
X		}
X	} while (k < e);
X	
X	return w;
X}
X
Xbufpos
Xtetextbreak(tp, pos, end, width)
X	register TEXTEDIT *tp;
X	bufpos pos, end;
X	int width;
X{
X	char *p= tp->buf + pos;
X	register char *e= tp->buf +
X		(tp->gap >= pos && tp->gap < end ? tp->gap : end);
X	int w= 0;
X	register char *k;
X	
X	zcheckpos(pos);
X	zcheckpos(end);
X	zassert(pos <= end);
X	
X	/* This do loop is executed once or twice only! */
X	do {
X		for (k= p; k < e; ++k) {
X			if (*k == '\t') {
X				if (k > p) {
X					int n= wtextbreak(p, (int)(k-p),
X						width-w);
X					if (n < k-p)
X						return p - tp->buf + n;
X					w += wtextwidth(p, (int)(k-p));
X				}
X				w= znexttab(w);
X				if (w > width)
X					return k - tp->buf;
X				p= k+1;
X			}
X		}
X		if (k > p) {
X			int n= wtextbreak(p, (int)(k-p), width-w);
X			if (n < k-p)
X				return p - tp->buf + n;
X			w += wtextwidth(p, (int)(k-p));
X		}
X		if (tp->gap >= pos) {
X			p= tp->buf + zgapend;
X			e= tp->buf + end;
X		}
X	} while (k < e);
X	
X	return end;
X}
X
Xhcoord
Xtedrawtext(tp, h, v, pos, end)
X	register TEXTEDIT *tp;
X	int h, v;
X	bufpos pos, end;
X{
X	char *p= tp->buf + pos;
X	register char *e= tp->buf +
X		(tp->gap >= pos && tp->gap < end ? tp->gap : end);
X	int w= 0;
X	register char *k;
X	
X	zcheckpos(pos);
X	zcheckpos(end);
X	zassert(pos <= end);
X	
X	/* This do loop is executed once or twice only! */
X	do {
X		for (k= p; k < e; ++k) {
X			if (*k == '\t') {
X				if (k > p)
X					wdrawtext(h+w, v, p, (int)(k-p));
X					w += wtextwidth(p, (int)(k-p));
X				w= znexttab(w);
X				p= k+1;
X			}
X		}
X		if (k > p) {
X			wdrawtext(h+w, v, p, (int)(k-p));
X			w += wtextwidth(p, (int)(k-p));
X		}
X		if (tp->gap >= pos) {
X			p= tp->buf + zgapend;
X			e= tp->buf + end;
X		}
X	} while (k < e);
X	
X	return h+w;
X}
X
X/* Safe memory allocation - these abort instead of returning NULL */
X
Xchar *
Xzmalloc(n)
X	int n;
X{
X	char *p= malloc((unsigned)n);
X	
X	if (p == NULL) {
X		dprintf("zmalloc(%d): out of mem", n);
X		exit(1);
X	}
X	return p;
X}
X
Xchar *
Xzrealloc(p, n)
X	char *p;
X	int n;
X{
X	char *q= realloc(p, (unsigned)n);
X	if (q == NULL) {
X		dprintf("zrealloc(0x%lx, %d): out of mem", (long)p, n);
X		exit(1);
X	}
X	return q;
X}
X
X/* Create/destroy a text-edit record */
X
XTEXTEDIT *
Xtealloc(win, left, top, width)
X	WINDOW *win;
X{
X	return tesetup(win, left, top, left+width, top, TRUE);
X}
X
XTEXTEDIT *
Xtecreate(win, left, top, right, bottom)
X	WINDOW *win;
X	int left, top, right, bottom;
X{
X	return tesetup(win, left, top, right, bottom, TRUE);
X}
X
X/*ARGSUSED*/
XTEXTEDIT *
Xtesetup(win, left, top, right, bottom, drawing)
X	WINDOW *win;
X	int left, top, right, bottom;
X	bool drawing;
X{
X	TEXTEDIT *tp= (TEXTEDIT*) zmalloc(sizeof(TEXTEDIT));
X	TEXTATTR saveattr;
X	
X	tp->win= win;
X	tp->left= left;
X	tp->top= top;
X	tp->right= right;
X	tp->width= right-left;
X	
X	wgettextattr(&saveattr);
X	if (win != NULL) {
X		wgetwintextattr(win, &tp->attr);
X		wsettextattr(&tp->attr);
X	}
X	else
X		tp->attr = saveattr;
X	tp->vspace= wlineheight();
X	tp->tabsize= 8*wcharwidth(' ');
X	if (win != NULL)
X		wsettextattr(&saveattr);
X	
X	tp->bottom= tp->top + tp->vspace;
X	
X	tp->foc= tp->foclen= 0;
X	
X	tp->buflen= 1;
X	tp->buf= zmalloc(tp->buflen);
X	
X	tp->gap= 0;
X	tp->gaplen= tp->buflen;
X	
X	tp->nlines= 1;
X	tp->nstart= STARTINCR;
X	tp->start= (bufpos*) zmalloc(tp->nstart*sizeof(bufpos));
X	tp->start[0]= tp->start[1]= tp->buflen;
X	
X	tp->aim= UNDEF;
X	tp->focprev= FALSE;
X	tp->hilite= FALSE;
X	tp->mdown= FALSE;
X	tp->drawing= tp->active= drawing;
X	tp->opt_valid= FALSE;
X	
X	if (tp->active)
X		tesetcaret(tp);
X	
X	zcheck();
X	
X	return tp;
X}
X
X
Xvoid
Xtedestroy(tp)
X	register TEXTEDIT *tp;
X{
X	wchange(tp->win, tp->left, tp->top, tp->right, tp->bottom);
X	tefree(tp);
X}
X
Xvoid
Xtefree(tp)
X	register TEXTEDIT *tp;
X{
X	if (tp->active) {
X		wnocaret(tp->win);
X		tehidefocus(tp);
X	}
X	if (tp->buf != NULL)
X		free(tp->buf);
X	if (tp->start != NULL)
X		free((char*)tp->start);
X	free((char*)tp);
X}
X
Xvoid
Xtesetactive(tp, active)
X	register TEXTEDIT *tp;
X	bool active;
X{
X	if (!tp->drawing || tp->active == active)
X		return;
X	tp->active = active;
X	if (active) {
X		tesetcaret(tp);
X	}
X	else {
X		wnocaret(tp->win);
X		tehidefocus(tp);
X	}
X}
X
X/* Show/hide the focus highlighting.
X   The boolean hilite is set when highlighting is visible.
X   teshowfocus ensures the highlighting is visible (if applicable);
X   tehidefocus ensures it is invisible.
X   teinvertfocus does the hard work (it is also called from zdraw) */
X
Xteshowfocus(tp)
X	register TEXTEDIT *tp;
X{
X	if (tp->active && !tp->hilite && tp->foclen > 0) {
X		wbegindrawing(tp->win);
X		teinvertfocus(tp);
X		wenddrawing(tp->win);
X		tp->hilite= TRUE;
X	}
X}
X
Xtehidefocus(tp)
X	register TEXTEDIT *tp;
X{
X	if (tp->hilite) {
X		wbegindrawing(tp->win);
X		teinvertfocus(tp);
X		wenddrawing(tp->win);
X		tp->hilite= FALSE;
X	}
X}
X
Xstatic
Xteinvertfocus(tp)
X	register TEXTEDIT *tp;
X{
X	teinvert(tp, tp->foc, zfocend);
X}
X
X/* Change to a new focus.
X   Sometimes this may keep the focus visible, sometimes not. */
X
Xtechangefocus(tp, f1, f2)
X	register TEXTEDIT *tp;
X	int f1, f2;
X{
X	if (tp->hilite) {
X		wbegindrawing(tp->win);
X		if (f1 == tp->foc)
X			teinvert(tp, zfocend, f2);
X		else if (f2 == zfocend)
X			teinvert(tp, f1, tp->foc);
X		else {
X			teinvert(tp, tp->foc, zfocend);
X			tp->hilite= FALSE;
X		}
X		wenddrawing(tp->win);
X	}
X	tp->foc= f1;
X	tp->foclen= f2-f1;
X}
X
X/* Low-level interface: invert the area between f1 and f2 */
X
Xstatic
Xteinvert(tp, f1, f2)
X	register TEXTEDIT *tp;
X	int f1, f2;
X{
X	coord h, v, hlast, vlast;
X	
X	if (f1 == f2)
X		return;
X	if (f2 < f1) {
X		int temp= f1;
X		f1= f2;
X		f2= temp;
X	}
X	
X	tewhichpoint(tp, f1, &h, &v);
X	tewhichpoint(tp, f2, &hlast, &vlast);
X	
X	if (v == vlast)
X		winvert(h, v, hlast, v + tp->vspace);
X	else {
X		winvert(h, v, tp->right, v + tp->vspace);
X		winvert(tp->left, v + tp->vspace, tp->right, vlast);
X		winvert(tp->left, vlast, hlast, vlast + tp->vspace);
X	}
X}
X
X/* Draw procedure */
X
Xvoid
Xtedraw(tp)
X	register TEXTEDIT *tp;
X{
X	tedrawnew(tp, tp->left, tp->top, tp->right, tp->bottom);
X}
X
X/*ARGSUSED*/
Xvoid
Xtedrawnew(tp, left, top, right, bottom)
X	register TEXTEDIT *tp;
X	coord left, top, right, bottom;
X{
X	lineno ifirst, ilast, i;
X	
X	/* Compute first, last line to be drawn */
X	ifirst= (top - tp->top)/tp->vspace;
X	if (ifirst < 0)
X		ifirst= 0;
X	ilast= (bottom - tp->top + tp->vspace - 1)/tp->vspace;
X	if (ilast > tp->nlines)
X		ilast= tp->nlines;
X	
X	/* Draw lines ifirst...ilast-1 */
X	for (i= ifirst; i < ilast; ++i) {
X		bufpos pos= tp->start[i];
X		bufpos 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		(void) tedrawtext(tp, tp->left, tp->top + i*tp->vspace,
X			pos, end);
X	}
X	if (tp->hilite)
X		teinvertfocus(tp);
X}
X
X/* Move the gap to a new position */
X
Xtemovegapto(tp, newgap)
X	register TEXTEDIT *tp;
X	bufpos newgap;
X{
X	zcheck();
X	zassert(0<=newgap && newgap+tp->gaplen<=tp->buflen);
X	
X	if (newgap < tp->gap)
X		teshift(tp, tp->gaplen, newgap, tp->gap);
X	else if (newgap > tp->gap)
X		teshift(tp, -tp->gaplen, zgapend, newgap+tp->gaplen);
X	tp->gap= newgap;
X	
X	zcheck();
X}
X
X/* Extend the gap */
X
Xtegrowgapby(tp, add)
X	register TEXTEDIT *tp;
X	int add;
X{
X	zcheck();
X	zassert(add>=0);
X	
X	tp->buf= zrealloc(tp->buf, tp->buflen + add);
X	teshift(tp, add, zgapend, tp->buflen);
X	tp->gaplen += add;
X	if (tp->start[tp->nlines-1] == tp->buflen)
X		tp->start[tp->nlines-1]= tp->buflen+add;
X	tp->start[tp->nlines]= (tp->buflen += add);
X	
X	zcheck();
X}
X
X/* Shift buf[first..last-1] n bytes (positive right, negative left) */
X
Xstatic
Xteshift(tp, n, first, last)
X	register TEXTEDIT *tp;
X	int n;
X	bufpos first, last;
X{
X	teoffset(tp, n, first, last);
X	if (n < 0)
X		temovedown(tp, last-first, tp->buf+first, tp->buf+first+n);
X	else if (n > 0)
X		temoveup(tp, last-first, tp->buf+first, tp->buf+first+n);
X}
X
Xstatic
Xteoffset(tp, n, first, last)
X	register TEXTEDIT *tp;
X	int n;
X	int first, last;
X{
X	int i;
X	
X	zassert(0<=first&&first<=last&&last<=tp->buflen);
X	
X	i= 0;
X	while (tp->start[i] < first)
X		++i;
X	while (tp->start[i] < last) {
X		tp->start[i] += n;
X		++i;
X	}
X}
X
X/*ARGSUSED*/
Xstatic
Xtemoveup(tp, n, from, to)
X	TEXTEDIT *tp;
X	int n;
X	char *from, *to;
X{
X	zassert(from <= to);
X	
X	from += n, to += n;
X	while (--n >= 0)
X		*--to = *--from;
X}
X
X/*ARGSUSED*/
Xstatic
Xtemovedown(tp, n, from, to)
X	TEXTEDIT *tp;
X	int n;
X	char *from, *to;
X{
X	zassert(from >= to);
X	
X	while (--n >= 0)
X		*to++ = *from++;
X}
X
X/* Make all start entries pointing into the gap point to beyond it
X   TO DO: replace by a routine to delete the focus??? */
X
Xteemptygap(tp)
X	register TEXTEDIT *tp;
X{
X	lineno i;
X	
X	for (i= 0; tp->start[i] < tp->gap; ++i)
X		;
X	for (; tp->start[i] < zgapend; ++i)
X		tp->start[i]= zgapend;
X}
X
X/* Set the caret at the new focus position,
X   or display the focus highlighting, if applicable.
X   Also call wshow() of the focus.
X   As a side effect, the optimization data is invalidated */
X
Xtesetcaret(tp)
X	register TEXTEDIT *tp;
X{
X	coord h, v, hlast, vlast;
X	
X	tp->opt_valid = FALSE;
X	if (!tp->active)
X		return;
X	
X	tewhichpoint(tp, tp->foc, &h, &v);
X	
X	if (tp->foclen == 0) {
X		wsetcaret(tp->win, h, v);
X		hlast= h;
X		vlast= v;
X	}
X	else {
X		tewhichpoint(tp, zfocend, &hlast, &vlast);
X		wnocaret(tp->win);
X		teshowfocus(tp);
X	}
X	wshow(tp->win, h, v, hlast, vlast + tp->vspace);
X}
X
X/* Coordinate transformations.
X   The following coordinate systems exist;
X   a position in the text can be expressed in any of these:
X   
X   	A) offset in buffer with gap removed (used for focus)
X	B) offset in buffer (used for start[] array)
X	C) (line number, offset in line taking gap into account)
X	D) (h, v) on screen
X   
X   Conversions exist between successive pairs:
X   
X   	A -> B: pos= zaddgap(foc)
X	B -> A: foc= zsubgap(pos)
X	
X	B -> C: line= zwhichline(pos, prev); offset= pos-start[line]
X	C -> B: pos= offset + start[line]
X	
X	C -> D: v= i*vspace; h= ztextwidth(start[i], start[i]+offset)
X	D -> C: i= v/wlh; offset= ztextround(i, h) - start[i]
X*/
X
X/* Find (h, v) corresponding to focus position */
X
Xtewhichpoint(tp, f, h_ret, v_ret)
X	TEXTEDIT *tp;
X	focpos f;
X	coord *h_ret, *v_ret;
X{
X	bufpos pos= zaddgap(f);
X	lineno i= tewhichline(tp, pos, f == tp->foc && tp->focprev);
X	hcoord h= tetextwidth(tp, tp->start[i], pos);
X	
X	*h_ret= h + tp->left;
X	*v_ret= i*tp->vspace + tp->top;
X}
X
X/* To which line does the given buffer position belong? */
X
Xlineno
Xtewhichline(tp, pos, prev)
X	register TEXTEDIT *tp;
X	bufpos pos;
X	bool prev; /* Cf. focprev */
X{
X	lineno i;
X	
X	for (i= 0; pos > tp->start[i+1]; ++i)
X		;
X	if (pos == tp->start[i+1] && i+1 < tp->nlines) {
X		++i;
X		if (prev && zcharbefore(tp->start[i]) != EOL)
X			--i;
X	}
X	
X	return i;
X}
X
X/* Convert point in window to buffer position,
X   possibly taking double-clicking into account.
X   If required, the line number is also returned. */
X
Xbufpos
Xtewhereis(tp, h, v, line_return)
X	register TEXTEDIT *tp;
X	coord h, v;
X	int *line_return;
X{
X	bufpos pos;
X	lineno i;
X	
X	i= (v - tp->top)/tp->vspace;
X	if (i >= tp->nlines) {
X		i= tp->nlines;
X		pos= tp->buflen;
X	}
X	else if (i < 0) {
X		i= 0;
X		pos= 0;
X	}
X	else
X		pos= tetextround(tp, i, h);
X	if (line_return != NULL)
X		*line_return= i;
X	return pos;
X}
X
X/* Find the buffer position nearest to the given h coordinate,
X   in the given line */
X
Xbufpos
Xtetextround(tp, i, h)
X	register TEXTEDIT *tp;
X	lineno i;
X	hcoord h;
X{
X	bufpos pos;
X	bufpos end= tp->start[i+1];
X	
X	h -= tp->left;
X	if (end > tp->start[i] && zcharbefore(end) == EOL)
X		zdecr(&end);
X	pos= tetextbreak(tp, tp->start[i], end, h);
X	
X	if (pos < end) {
X		if (h - tetextwidth(tp, tp->start[i], pos) >=
X			tetextwidth(tp, tp->start[i], znext(pos)) - h)
X			zincr(&pos);
X	}
X	
X	return pos;
X}
END_OF_FILE
if test 12558 -ne `wc -c <'Packs/textedit/textlow.c'`; then
    echo shar: \"'Packs/textedit/textlow.c'\" unpacked with wrong size!
fi
# end of 'Packs/textedit/textlow.c'
fi
if test -f 'Ports/mac/event.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/mac/event.c'\"
else
echo shar: Extracting \"'Ports/mac/event.c'\" \(12997 characters\)
sed "s/^X//" >'Ports/mac/event.c' <<'END_OF_FILE'
X/* MAC STDWIN -- EVENT HANDLING. */
X
X#include "macwin.h"
X#ifdef MPW
X#include <Events.h>
X#include <Menus.h>
X#include <Desk.h>
X#include <ToolUtils.h>
X#endif
X#ifdef THINK_C
X#include <EventMgr.h>
X#endif
X
Xvoid (*_w_idle_proc)();	/* Function to call in idle loop */
X
XWINDOW *active= NULL;	/* The active window */
X			/* XXX should be a less obvious name */
Xbool _wm_down;		/* Set if mouse is down in content rect */
X
Xstatic EventRecord e;	/* Global, so it's accessible to all subroutines */
X			/* XXX the name is too short */
X
X/* Function prototypes */
X
XSTATIC void make_mouse_event _ARGS((EVENT *ep, Point *pwhere));
XSTATIC void do_idle _ARGS((EVENT *ep));
XSTATIC void do_update _ARGS((EVENT *ep));
XSTATIC void do_mouse_down _ARGS((EVENT *ep));
XSTATIC void do_mouse_up _ARGS((EVENT *ep));
XSTATIC void do_key _ARGS((EVENT *ep));
XSTATIC void do_activate _ARGS((EVENT *ep));
XSTATIC void do_disk _ARGS((EVENT *ep));
XSTATIC void activate _ARGS((WINDOW *win));
XSTATIC void deactivate _ARGS((void));
X
XSTATIC void do_click _ARGS((EVENT *ep, WindowPtr w));
XSTATIC void do_unclick _ARGS((EVENT *ep));
XSTATIC void do_drag _ARGS((WindowPtr w));
XSTATIC void do_grow _ARGS((EVENT *ep, WindowPtr w));
XSTATIC void do_goaway _ARGS((EVENT *ep, WindowPtr w));
XSTATIC void do_zoom _ARGS((EVENT *ep, WindowPtr w, int code));
XSTATIC void do_size _ARGS((EVENT *ep, WindowPtr w));
X
X# ifndef NO_STDIO
X/* Some applications (e.g., Python) want events passed to the stdio console.
X   They must call wsetstdio(1) before their first wgetevent() call. */
X
Xstatic int pass_to_stdio = 0;
X
Xvoid
Xwsetstdio(flag)
X	int flag;
X{
X	pass_to_stdio = flag;
X}
X#endif
X
Xstatic EVENT pushback= {WE_NULL};
X
Xvoid
Xwungetevent(ep)
X	EVENT *ep;
X{
X	pushback= *ep;
X}
X
Xstatic void
Xwwaitevent(ep, wait)
X	EVENT *ep;
X	bool wait;
X{
X	_wfreeclip();
X	if (pushback.type != WE_NULL) {
X		*ep= pushback;
X		pushback.type= WE_NULL;
X		return;
X	}
X	
X	if (_wmenuhilite) {
X		HiliteMenu(0);
X		_wmenuhilite= FALSE;
X	}
X	
X	if (active == NULL)
X		set_arrow();
X	
X	ep->type= WE_NULL;
X	ep->window= NULL;
X	
X	do {
X		if (!GetNextEvent(everyEvent, &e)) {
X			if (e.what == nullEvent) {
X				if (wait) do_idle(ep);
X				else return;
X			}
X		}
X		else {
X#ifndef NO_STDIO
X			/* Give THINK C stdio a chance to handle the event.
X			   Unfortunately it also eats up clicks in
X			   title bars, so, to save our Option-click feature,
X			   we don't feed it those. */
X			if (pass_to_stdio &&
X					!(e.what == mouseDown &&
X					  (e.modifiers & optionKey))) {
X				if (StdEvent(&e))
X					continue;
X			}
X#endif
X			switch (e.what) {
X			case mouseDown:
X				do_mouse_down(ep);
X				break;
X			case mouseUp:
X				do_mouse_up(ep);
X				break;
X			case keyDown:
X			case autoKey:
X				do_key(ep);
X				break;
X			case updateEvt:
X				do_update(ep);
X				break;
X			case diskEvt:
X				do_disk(ep);
X				break;
X			case activateEvt:
X				do_activate(ep);
X				break;
X			}
X		}
X	} while (ep->type == WE_NULL);
X	
X	if (ep->window == NULL)
X		ep->window= whichwin(FrontWindow());
X	if (!_wm_down)
X		set_watch();
X}
X
Xint
Xwpollevent(ep)
X        EVENT *ep;
X{
X        ep->type = WE_NULL;
X        wwaitevent(ep, FALSE);
X        return ep->type != WE_NULL;
X}
X
Xvoid
Xwgetevent(ep)
X        EVENT *ep;
X{
X        wwaitevent(ep, TRUE);
X}
X
Xstatic void
Xdo_idle(ep)
X	EVENT *ep;
X{	
X	if (checktimer(ep))
X		return;
X	
X	if (_w_idle_proc != NULL)
X		(*_w_idle_proc)();
X	
X	/* The user idle proc may have called wungetevent: */
X	if (pushback.type != WE_NULL) {
X		*ep= pushback;
X		pushback.type= WE_NULL;
X		return;
X	}
X	
X	SystemTask();
X	
X	if (active != NULL) {
X		Point where;
X		Rect r;
X		
X		where= e.where;
X		SetPort(active->w);
X		GlobalToLocal(&where);
X		if (_wm_down) {
X			autoscroll(active, where.h, where.v);
X			make_mouse_event(ep, &where);
X			return;
X		}
X		getwinrect(active, &r);
X		if (PtInRect(PASSPOINT where, &r)) {
X			if (e.modifiers & optionKey)
X				set_hand();
X			else
X				set_applcursor();
X		}
X		else
X			set_arrow();
X		blinkcaret(active);
X	}
X}
X
Xstatic void
Xdo_update(ep)
X	EVENT *ep;
X{
X	WINDOW *win;
X	Rect r;
X	
X	win= whichwin((WindowPtr) e.message);
X	if (win == NULL) {
X		/* dprintf("update evt for alien window"); */
X		return;
X	}
X	_wupdate(win, &r);
X	if (win->drawproc == NULL && !EmptyRect(&r)) {
X		ep->type= WE_DRAW;
X		ep->window= win;
X		ep->u.area.left= r.left;
X		ep->u.area.top= r.top;
X		ep->u.area.right= r.right;
X		ep->u.area.bottom= r.bottom;
X	}
X}
X
Xstatic void
Xdo_mouse_down(ep)
X	EVENT *ep;
X{
X	WindowPtr w;
X	int code= FindWindow(PASSPOINT e.where, &w);
X	
X	/* XXX This doesn't look incredibly necessary:
X	if (active != NULL) {
X		SetPort(active->win);
X		rmcaret(active);
X	}
X	*/
X	
X	if (code != inContent && code != inSysWindow)
X		set_arrow();
X	switch (code) {
X	case inMenuBar:
X		_wdo_menu(ep, MenuSelect(PASSPOINT e.where));	
X		break;
X	case inSysWindow:
X		SystemClick(&e, w);
X		break;
X	case inContent:
X		do_click(ep, w);
X		break;
X	case inDrag:
X		do_drag(w);
X		break;
X	case inGrow:
X		do_grow(ep, w);
X		break;
X	case inGoAway:
X		do_goaway(ep, w);
X		break;
X	case inZoomIn:
X	case inZoomOut:
X		do_zoom(ep, w, code);
X		break;
X	}
X}
X
Xstatic void
Xdo_mouse_up(ep)
X	EVENT *ep;
X{
X	do_unclick(ep);
X}
X
Xstatic void
Xdo_key(ep)
X	EVENT *ep;
X{
X	char c= e.message & charCodeMask;
X	
X	/* XXX shouldn't mess at all with non-stdwin windows */
X	
X	if (e.modifiers & cmdKey) {
X		if (c == '.') {
X			ep->type= WE_COMMAND;
X			ep->u.command= WC_CANCEL;
X		}
X		else
X			_wdo_menu(ep, MenuKey(c));
X	}
X	else {
X		ep->type= WE_COMMAND;
X		switch (c) {
X		
X		default:
X			ObscureCursor();
X			ep->type= WE_CHAR;
X			ep->u.character= c;
X			break;
X		
X		case LEFT_ARROW:
X		case RIGHT_ARROW:
X		case UP_ARROW:
X		case DOWN_ARROW:
X			ep->u.command= c-LEFT_ARROW + WC_LEFT;
X			break;
X		
X		case '\b':
X			ObscureCursor();
X			ep->u.command= WC_BACKSPACE;
X			break;
X		
X		case '\t':
X			ObscureCursor();
X			ep->u.command= WC_TAB;
X			break;
X		
X		case '\r':
X		case ENTER_KEY:
X			ep->u.command= WC_RETURN;
X			break;
X		
X		}
X	}
X}
X
Xstatic void
Xdo_disk(ep)
X	EVENT *ep;
X{
X	/* XXX Disk events not implemented -- who cares. */
X}
X
X/* XXX Need to be easier for cases where we seem to have missed events */
X
Xstatic void
Xdo_activate(ep)
X	EVENT *ep;
X{
X	WINDOW *win= whichwin((WindowPtr)e.message);
X	
X	if (win == NULL) {
X		/* dprintf("(de)activate evt for alien window"); */
X		return;
X	}
X	
X	if (e.modifiers & activeFlag) { /* Activation */
X		if (active != NULL) {
X			/* Perhaps reactivation after modal dialog */
X#ifdef NO_STDIO
X			/* But perhaps THINK C stdio is fooling us */
X			if (active == win)
X				return;
X			/* If we get here we've missed a
X			   deactivate event... */
X			dprintf("activate without deactivate");
X#endif
X		}
X		activate(win);
X		ep->type= WE_ACTIVATE;
X		ep->window= active;
X	}
X	else { /* Deactivation */
X		if (win != active) {
X			/* Spurious deactivation event.
X			   This always happens when we open
X			   two or more windows without intervening
X			   call to wgetevent().
X			   Perhaps an conscious hack in the
X			   ROM to "help" programs that believe
X			   windows are created active? */
X			return;
X		}
X		ep->type= WE_DEACTIVATE;
X		ep->window= active;
X		deactivate();
X	}
X}
X
Xstatic void
Xdeactivate()
X{
X	SetPort(active->w);
X	rmcaret(active);
X	hidescrollbars(active);
X	rmlocalmenus(active);
X	DrawGrowIcon(active->w);
X	active= NULL;
X	set_arrow();
X}
X
Xstatic void
Xactivate(win)
X	WINDOW *win;
X{
X	if (active != NULL)
X		deactivate();
X	if (win != NULL) {
X		SetPort(win->w);
X		active= win;
X		showscrollbars(win);
X		addlocalmenus(active);
X		valid_border(win->w); /* Avoid flicker when window pops up */
X	}
X}
X
Xstatic void
Xdo_click(ep, w)
X	EVENT *ep;
X	WindowPtr w;
X{
X	WINDOW *win= whichwin(w);
X	Point where;
X	int pcode;
X	ControlHandle bar;
X	
X	if (win == NULL) {
X		/* dprintf("click in alien window"); */
X		return;
X	}
X	if (win != active) {
X		set_arrow();
X		if (e.modifiers & optionKey) {
X			/* Option-click sends a window behind. */
X			SendBehind(w, (WindowPtr) NULL);
X		}
X		else
X			SelectWindow(win->w);
X		return;
X		/* Let activate events do the rest. */
X	}
X	where= e.where;
X	SetPort(win->w);
X	GlobalToLocal(&where);
X	pcode= FindControl(PASSPOINT where, w, &bar);
X	if (pcode != 0) {
X		set_arrow();
X		do_scroll(&where, win, bar, pcode);
X	}
X	else {
X		Rect r;
X		
X		getwinrect(win, &r);
X		if (PtInRect(PASSPOINT where, &r)) {
X			if (e.modifiers & optionKey) {
X				set_hand();
X				dragscroll(win,
X					where.h, where.v,
X					e.modifiers & shiftKey);
X			}
X			else {
X				set_applcursor();
X				make_mouse_event(ep, &where);
X			}
X		}
X	}
X}
X
Xstatic void
Xdo_unclick(ep)
X	EVENT *ep;
X{
X	if (active != NULL) {
X		Point where;
X		
X		where= e.where;
X		SetPort(active->w);
X		GlobalToLocal(&where);
X		make_mouse_event(ep, &where);
X	}
X}
X
Xstatic void
Xdo_drag(w)
X	WindowPtr w;
X{
X	if (e.modifiers & optionKey) {
X		/* Nonstandard: option-click sends a window behind. */
X		SendBehind(w, (WindowPtr) NULL);
X	}
X	else {
X		Rect r;
X		
X		r= screen->portRect;
X		r.top += MENUBARHEIGHT;
X		InsetRect(&r, 4, 4);
X		DragWindow(w, PASSPOINT e.where, &r);
X	}
X}
X
Xstatic void
Xdo_grow(ep, w)
X	EVENT *ep;
X	WindowPtr w;
X{
X	Rect r;
X	long reply;
X	
X	/* XXX shouldn't mess at all with non-stdwin windows */
X	
X	/* Set minimal window size */
X	r.left= LSLOP + MIN_WIDTH + RSLOP + BAR;
X	r.top= MIN_HEIGHT + BAR;
X	
X	/* The max size is derived from the document size.
X	   If there is no document size, it is unlimited.
X	   (There is nothing wrong with windows larger than
X	   the screen, really.) */
X	r.right = r.bottom = 0x7fff;
X	{
X		/* Max size restriction based on doc size, if specified */
X		WINDOW *win = whichwin(w);
X		int docwidth = win->docwidth;
X		int docheight = win->docheight;
X		if (win->docwidth > 0) {
X			CLIPMIN(docwidth, MIN_WIDTH);
X			r.right = LSLOP + docwidth + RSLOP + BAR + 1;
X		}
X		if (win->docheight > 0) {
X			CLIPMIN(docheight, MIN_HEIGHT);
X			r.bottom = docheight + BAR + 1;
X		}
X		/* For some reason 1 has to be added.  Sigh. */
X	}
X	
X	reply= GrowWindow(w, PASSPOINT e.where, &r);
X	if (reply != 0) {
X		SetPort(w);
X		inval_border(w);
X		SizeWindow(w, LoWord(reply), HiWord(reply), TRUE);
X		do_size(ep, w);
X	}
X}
X
Xstatic void
Xdo_goaway(ep, w)
X	EVENT *ep;
X	WindowPtr w;
X{
X	/* XXX shouldn't mess at all with non-stdwin windows */
X	
X	if (TrackGoAway(w, PASSPOINT e.where)) {
X		ep->type= WE_COMMAND;
X		ep->window= whichwin(w);
X		ep->u.command= WC_CLOSE;
X	}
X}
X
Xstatic void
Xdo_zoom(ep, w, code)
X	EVENT *ep;
X	WindowPtr w;
X	int code;
X{
X	/* XXX shouldn't mess at all with non-stdwin windows */
X	
X	/* This code will never be reached on a machine
X	   with old (64K) ROMs, because FindWindow will
X	   never return inZoomIn or inZoomOut.
X	   Therefore, no check for new ROMs is necessary.
X	   A warning in Inside Macintosh IV says that
X	   it is necessary to make the zoomed window
X	   the current GrafPort before calling ZoomWindow.
X	   True enough, it fails spectacularly otherwise,
X	   but still this looks like a bug to me - there
X	   are no similar requirements for SizeWindow
X	   or DragWindow. */
X	
X	SetPort(w);
X	if (TrackBox(w, PASSPOINT e.where, code)) {
X		inval_border(w);
X		ZoomWindow(w, code, TRUE);
X		do_size(ep, w);
X	}
X}
X
X/* do_size assumes w is already the current grafport */
X
Xstatic void
Xdo_size(ep, w)
X	EVENT *ep;
X	WindowPtr w;
X{
X	WINDOW *win= whichwin(w);
X	
X	if (win == NULL) {
X		/* dprintf("alien window resized"); */
X		return;
X	}
X	inval_border(w);
X	movescrollbars(win);
X	ep->type= WE_SIZE;
X	ep->window= win;
X	_wfixorigin(win);
X}
X
Xvoid
Xinval_border(w)
X	WindowPtr w;
X{
X	Rect r;
X	
X	r= w->portRect;
X	r.left= r.right - BAR;
X	InvalRect(&r);
X	r= w->portRect;
X	r.top= r.bottom - BAR;
X	InvalRect(&r);
X}
X
Xvoid
Xvalid_border(w)
X	WindowPtr w;
X{
X	Rect r;
X	
X	r= w->portRect;
X	r.left= r.right - BAR;
X	ValidRect(&r);
X	r= w->portRect;
X	r.top= r.bottom - BAR;
X	ValidRect(&r);
X}
X
X/* Variables needed in click and move detection. */
X
Xstatic int m_h, m_v;		/* Doc. coord. of last mouse evt. */
Xstatic long m_when;		/* TickCount of last mouse evt. */
Xstatic int m_clicks;		/* N-fold click stage */
Xstatic int m_button;		/* Which 'button';
X				   1=normal, 2=shift, 3=command. */
X
Xstatic void
Xmake_mouse_event(ep, pwhere)
X	EVENT *ep;
X	Point *pwhere;		/* Mouse pos. in local coord. */
X{
X	WINDOW *win= active;
X	int h= pwhere->h + win->orgh;
X	int v= pwhere->v + win->orgv;
X	int dh= h - m_h;
X	int dv= v - m_v;
X	
X	if (dh*dh + dv*dv > CLICK_DIST*CLICK_DIST)
X		m_clicks= 0;	/* Moved too much for a click */
X	
X	if (e.what == mouseDown) {
X		if (e.when > m_when + GetDblTime())
X			m_clicks= 1;
X		else
X			++m_clicks;
X		ep->type= WE_MOUSE_DOWN;
X		_wm_down= TRUE;
X		/* XXX Should swap buttons 2 & 3 (also in textedit)
X		   since X11 (e.g., xterm) uses button 3 for extend */
X		m_button= (e.modifiers & cmdKey) ? 3 :
X			(e.modifiers & shiftKey) ? 2 : 1;
X	}
X	else if (e.what == mouseUp) {
X		if (!_wm_down)
X			return;
X		ep->type= WE_MOUSE_UP;
X		_wm_down= FALSE;
X	}
X	else {
X		if (!_wm_down || m_clicks > 0 || (dh == 0 && dv == 0))
X			return;
X		ep->type= WE_MOUSE_MOVE;
X	}
X	ep->u.where.h= m_h= h;
X	ep->u.where.v= m_v= v;
X	ep->u.where.clicks= m_clicks;
X	ep->u.where.button= m_button;
X	ep->u.where.mask= (ep->type == WE_MOUSE_UP) ? 0 : 1;
X	ep->window= win;
X	m_when= e.when;
X}
X
X/* Reset the mouse state.
X   Called when a dialog is started. */
X
Xvoid
X_wresetmouse()
X{
X	_wm_down= FALSE;
X}
END_OF_FILE
if test 12997 -ne `wc -c <'Ports/mac/event.c'`; then
    echo shar: \"'Ports/mac/event.c'\" unpacked with wrong size!
fi
# end of 'Ports/mac/event.c'
fi
if test -f 'Ports/mac/menu.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/mac/menu.h'\"
else
echo shar: Extracting \"'Ports/mac/menu.h'\" \(354 characters\)
sed "s/^X//" >'Ports/mac/menu.h' <<'END_OF_FILE'
X/* MAC STDWIN -- MENU DEFINITIONS. */
X
X/* Note -- struct menu isn't defined here.
X   MENU * is taken to be equivalent to MenuPtr, whenever appropriate.
X   I know this is a hack -- I'll fix it later. */
X
Xstruct menubar {
X	int nmenus;		/* Number of menus in the list */
X	MENU **menulist;	/* Pointer to list of MENU pointers */
X};
X
X#define APPLE_MENU 32000
END_OF_FILE
if test 354 -ne `wc -c <'Ports/mac/menu.h'`; then
    echo shar: \"'Ports/mac/menu.h'\" unpacked with wrong size!
fi
# end of 'Ports/mac/menu.h'
fi
echo shar: End of archive 8 \(of 19\).
cp /dev/null ark8isdone
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



More information about the Alt.sources mailing list