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

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

Archive-name: stdwin/part07

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 7 (of 19)."
# Contents:  Doc/vtrmdoc.ms Ports/mac/scroll.c Ports/x11/general.c
#   Ports/x11/llevent.c
# Wrapped by guido@voorn.cwi.nl on Mon Mar  4 12:37:26 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Doc/vtrmdoc.ms' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Doc/vtrmdoc.ms'\"
else
echo shar: Extracting \"'Doc/vtrmdoc.ms'\" \(14015 characters\)
sed "s/^X//" >'Doc/vtrmdoc.ms' <<'END_OF_FILE'
X.TL
X.if n .po 0
X.if n .ll 72
X.if n .nr LL 72n
X.if t .po 3.5c \" For LaserWriter only
XInterfacing to Keyboard and Screen with VTRM
X.br
X(Draft)
X.AU
XGuido van Rossum
X.AB
XSince both groups of `interns' at the ABC project will soon need to
Xinterface their editors to a terminal, here is a description of the VTRM
Xpackage, together with some hints on writing a simple displayer using
Xthis package.  Footnotes are used to indicate portions of the interface
Xthat may change in the future.
X.AE
X.SH
X1. Introduction
X.LP
XThe VTRM package can significantly ease terminal-independent input and
Xoutput for a screen-oriented program like a text editor, written in C.
XThere are
Xabout a dozen routines, with few and simple parameters, that allow
Xoptimized output to almost any ASCII terminal designed in the Western
Xhemisphere, and input of single characters without echoing.  Features
Xinclude adaptation to any screen size, scrolling, and inverse video or a
Xsimilar `stand-out' mode of displaying selected characters.  Screen
Xrefreshes use available terminal features such as character insert or
Xdelete to minimize the number of characters actually output to the
Xterminal, thus obtaining reasonable performance even at low baud rates.
X.PP
XImplementations of the VTRM package are available for
X.UX ,
XMS-DOS and the Apple Macintosh, and the package can be ported to
Xother similar micro-computers.  It is also possible to write an
Xinterface to windowing systems like those found on Sun or Whitechapel
Xworkstations.
X.SH
X2. Theory of operation
X.LP
XVTRM is a set of subroutines callable from a C program.  There is a
Xcertain discipline required in calling these routines; there are
Xan initialization call, several data manipulation and input calls, and a
Xclean-up call.  The C program that is making the calls to VTRM is
Xfurther referred to as `the application'.  In fact, on different
Xsystems, different soubroutines are used; but they all conform to the
Xsame interface, which is what is described in this document.
X.PP
XVTRM has a simple model for a terminal screen: there are YMAX lines,
Xeach consisting XMAX characters.  YMAX and XMAX are not constants,
Xbut remain constant during one particular program run.*
X.FS
X*This causes problems with resizable windows as currently available
Xunder 4.3 BSD.  It is possible that future versions can adapt themselves
Xto changing window sizes, but this will require adaptation of the
Xprograms calling VTRM.
X.FE
X.PP
XThe coordinate system used by VTRM is different from that normally used
Xin geometry, but more convenient for referencing screen positions:
Xwhereever a position on the screen is referenced, it has the form (Y, X)
Xwhere Y is the line number and X is the column number.  The top line is
Xline 0, the bottom line is YMAX\-1.  Likewise, the leftmost
Xcolumn is column 0, the rightmost is XMAX\-1.  (Note how this is
Xcompatible with array indexing practices in C.) **
X.FS
X** This will get us into trouble with bit-mapped displays, where often
Xthe preferred character set or `font' has characters of different
Xwidths, so that the number of characters displayable on a line is not a
Xconstant.  This issue is ignored by VTRM; implementations on such
Xsystems currently use a `fixed-width' font.
X.FE
X.PP
XEach character position contains one character, which is in the ASCII
Xrange SPACE to `~', i.e., SPACE and all printable characters.  Each
Xcharacter can be displayed in one of two modes: normal or `stand-out',
Xwhich is usually inverse video or underlined (this is a choice made by
Xthe VTRM package).  `Empty' parts of the screen contain spaces in normal
Xmode. ***
X.FS
X*** Eventually the character set allowed will have to be extended to all
Xor most characters in the machine's standard character set that can be
Xdisplayed.  There is a tendency for systems to extend the 7-bit ASCII
Xcode to an 8-bit code, where the characters in the range 128-255 are
Xused for special graphics, accented characters etc.  VTRM currently uses
Xthe 8th bit to indicate stand-out mode; this will have to be changed in
Xthe interface.  Applications are discouraged to use the 8th bit of
Xcharacters as a `stand-out' flag except in the immediate interface with
XVTRM.
X.FE
X.PP
XVTRM is strongly line-oriented.  The application must offer data to VTRM
Xin chunks of one or more lines, and scrolling operations can only be
Xapplied to entire lines.  This is not likely to change in the near
Xfuture.  VTRM does not necessarily send whole lines to the screen: only
Xchanged parts of a line are actually transmitted.  VTRM recognizes most
Xcases of insertion or deletion of small strings in a line, which can
Xoften be handled with character insertions and/or deletions.
X.PP
XVTRM may buffer its output.  There is one routine which flushes the
Xbuffer and moves the terminal's cursor to a given (Y, X) position;
Xduring the screen update process the screen contents and cursor position
Xmay temporarily be undefined.  Not all implementations actually buffer
Xtheir output; micro-computer screen operations are often fast enough.
XIn all cases, the cursor position is undefined during the screen update.
X.PP
XVTRM does not automatically clear the screen when first called; it
Xallows an application to be written in such a manner that its output
Xappears at the bottom of the screen and gradually scrolls upwards,
Xmimicking the behaviour of older programs, if it so wishes.  On the
Xother hand, it is trivial to clear the screen after the first call.
X.PP
XOn
X.UX ,
XVTRM sets the terminal in a special mode (formally: cbreak, no echo, no
Xcr to nl mapping).  This makes it
Xnecessary that an application takes measures to call the VTRM clean-up
Xroutine whenever it exits.
X.PP
XOn
X.UX ,
XVTRM uses the `termcap' database to find out the terminal's
Xcapabilities.  It requires that the <:TERM:> environment variable is
Xset, and optionally acknowledges the <:TERMCAP:> variable.  Information
Xon the proper use of these variables should be readily accessible to all
Xusers of the application.
X.SH
X3. Description of the interface
X.SH
X3.1 Set-up and clean-up calls
X.SH
XTRMSTART
X.LP
X.DS
X<:int trmstart(p_lines, p_columns, p_flags)
Xint *p_lines, *p_columns;
Xint *p_flags;:>
X.DE
XThis call must be made before any of the other calls are allowed.  The
Xfunction result is 0 if initialization is successful, nonzero if an
Xerror occurred.  In the latter case the applications should usually
Xprint an error message and exit; the terminal state has not been
Xaltered.  The meaning of the error codes is described in the appendix.
X.PP
XThe three arguments must be the addresses of three integer variables
X(call as, e.g., <:trmstart(&lines, &columns, &flags):>).
XIn <:*p_lines:> and <:*p_columns:>, YMAX and XMAX are returned.
XIn <:*p_flags:>, some flag bits are returned, but these can usually be
Xignored by the applications (some flag bits are defined but never used).
X.SH
XTRMEND
X.LP
X.DS
X<:trmend();:>
X.DE
XThis function cleans up before the application exits.  If it is not
Xcalled (when <:trmstart:> has been called), the application may leave
Xthe terminal in a weird mode, from which it is hard to recover for the
Xuser (on
X.UX -systems non-
Xother weird things may happen).
X.PP
XSo that it can be safely called from within an interrupt handler,
X<:trmend:> may be called at any time, before or even during a call to
X<:trmstart:>.  Calls at any other time than after a successful call
Xto <:trmstart:> are ignored.  After a call to <:trmend:>, as before a
Xcall to <:trmstart:>, calls to all other routines of VTRM are forbidden
X(this is not enforced by all implementations \- but your program may
Xcrash).
X.PP
XAn application may engage in a sequence of interactive sessions, each
Xbracketed between calls to <:trmstart:> and <:trmend:>.  Outside these
Xsessions, normal print-style output can safely be used, thusly:
X.DS
X<:trmstart(...);
X\fIVTRM interaction 1\fP
Xtrmend();
Xprintf("Hello, world\\n"); /* Etc. */
Xtrmstart(...);
X\fIVTRM interaction 2\fP
Xtrmend();
X:><:...:>
X.DE
X.SH
X3.2 Output calls
X.SH
XTRMPUTDATA
X.LP
X.DS
X<:trmputdata(y0, y1, x, data)
Xint y0, y1;
Xint x;
Xchar *data;:>
X.DE
XThe characters in `data' are placed on the screen, starting at line y0,
Xposition x, and continuing up to the last position of line y1.  If data
Xis shorter than this space, the remaining positions are filled with
Xspaces; if tdata is too long, it is truncated.  The positions 0 through
Xx\-1 on line y0 are left unchanged.
X.PP
XCharacters with their 8th bit on (or-ed with 0200 octal or 0x80 hex)
Xare displayed in `stand-out' mode.
X.PP
XThe following is an easy way of clearing the screen:
X.DS
X<:trmputdata(0, YMAX-1, 0, "");:>
X.DE
X.SH
XTRMSCROLLUP
X.LP
X.DS
X<:trmscrollup(y0, y1, n)
Xint y0, y1;
Xint n;:>
X.DE
XScrolls the screen lines y0 to y1, inclusive, up by n lines.
XIf n is negative, it scrolls down.  When scrolling up, the top n lines
Xstarting at y0 disappear, the lines from y0+n to y1 move up n lines,
Xand n blank lines are `shifted in' at and above line y1.  Scrolling down
Xis similar.  If abs(n) > y1\-y0, lines y0 to y1 are blanked.
X.SH
XTRMSYNC
X.LP
X.DS
X<:trmsync(y, x)
Xint y, x;:>
X.DE
XCompletes any pending operations, flushes the output buffer, and moves
Xthe cursor to position (y, x) on the screen.
X.SH
XTRMUNDEFINED
X.LP
X.DS
X<:trmundefined();:>
X.DE
XTells VTRM to forget whatever it has remembered about the current screen
Xcontents.  This is necessary before doing a complete screen refresh in
Xresponse to a user command like control-L, since such a refresh is
Xusually intended to correct the effect of transmission errors or other
Xprocesses clobbering the screen.
X.SH
XTRMBELL
X.LP
X.DS
X<:trmbell();:>
X.DE
XIssues an alarm to the user in a way most appropriate to the output
Xdevice being used.  This may either be an audible bell or beep,
Xor a `visible bell', meaning a flash of (part of) the screen.
X.PP
X(On
X.UX ,
Xa control-G is sent to the terminal, unless the termcap entry specifies
Xthe `vb' property (visible bell).  On MS-DOS, the bell is sounded
Xunconditionally.  On the Macintosh, `SysBeep' is called, which gives a
Xbeep with a level determined by the volume control on the Control Panel,
Xor flashes the menu bar if the volume is set to 0.)
X.SH
X3.3 Input calls
X.SH
XTRMINPUT
X.LP
X.DS
X<:int trminput();:>
X.DE
XReturns the next input character typed at the keyboard, waiting if
Xnecessary until one is typed.  When an error occurs, \-1 is returned;
Xthis is usually permanent, so further input would be futile.  This could
Xhappen, for example, when the user `hangs up'.
X.SH
XTRMAVAIL
X.LP
X.DS
X<:int trmavail();:>
X.DE
XReturns 1 if an input character is immediately available for
X<:trminput:>; 0 if no such character is available; and \-1 if the system
Xcan't find out (this is not an error condition; it means that the system
Xcannot do a `non-blocking read').
X.SH
XTRMSENSE
X.LP
X.DS
X<:int trmsense(p_y, p_x)
Xint *p_y, *p_x;:>
X.DE
XSenses the current cursor or mouse position, and returns its position,
Xconverted to screen coordinates, in <:*p_y:> and <:*p_x:>.  If the
Xterminal is not capable of sensing the cursor position, both values are
Xset to \-1 and the functions returns 0; after a successful sense, the
Xfunction returns 1.
X.SH
X3.4 Interrupt handling calls
X.SH
XTRMINTERRUPT
X.LP
X.DS
X<:int trminterrupt();:>
X.DE
XChecks for keyboard-generated interrupt.  Returns 1 if one is found, 0
Xif not.  This may set a signal handler for <:SIGINT:>, so it may
Xinterfere with the application's signal handling.*  It may also flush
Xtype-ahead and (unfortunately enough) discard output buffers.
X.FS
X* This is an experimental feature.  Use at own risk.  Check the source
Xcode to see if its actually implemented, and how.
X.FE
X.SH
XTRMSUSPEND
X.LP
X.DS
X<:trmsuspend();:>
X.DE
XThis call does nothing except on Berkeley
X.UX
Xsupporting job control.  Because the terminal state and screen contents
Xare not restored when a process is suspended or resumed, programs using
XVTRM must be aware of suspension.  The character control-Z is received
Xas a normal input character by <:trminput:>, because <:trmstart:> turns
Xoff most special character processing.  When a control-Z is received,
Xthe application should react as follows:
X.DS
X<:trmend();
Xtrmsuspend();
Xtrmstart(...);
X\fIrepaint the screen\fR:>
X.DE
XThe <:trmsuspend:> call suspends the application and its `process group';
Xthis includes any subprocesses, and possibly parent processes (if the
Xapplication was run from a shell script or from another program, maybe
Xusing a `shell escape').  It only returns when the process group is resumed
Xagain (with the shell's `fg' command).
X.SH
X4. Examples
X.LP
XHere is a very small sample program:
X.DS
X<:main() {
X	int lines, columns, flags;
X	if (trmstart(&lines, &columns, &flags) != 0) exit(1);
X	trmputdata(0, lines-1, 0, "Hello, \\327orld!");
X	trmsync(1, 0);
X	trmend();
X	exit(0);
X}:>
X.DE
XIt prints the text <:Hello, \fBW\fRorld!:> at the top of the screen,
Xcleans the rest of the screen, and moves the cursor the the beginning of
Xthe second line.  The `W' is displayed in stand-out mode.
X.TL
XAppendix \- <:\fBtrmstart:> error codes and flags
X.sp 2
X.LP
XThe file "trm.h" can be included to get definitions for the flags and
Xerror codes returned by <:trmstart:>.  It contains the following:
X.sp 1
X.nf
X<:
X.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
X
X/*
X * Terminal capabilities.  These correspond to bits set by trmstart in its
X * parameter flags parameter.
X */
X
X#define HAS_STANDOUT	1	/* Terminal has inverse video or underline */
X#define CAN_SCROLL	2	/* Terminal can insert/delete lines */
X#define CAN_OPTIMISE	4	/* Terminal can insert/delete characters */
X#define CAN_SENSE	8	/* Terminal can send cursor position */
X
X/*
X * Error codes returned by trmstart.
X */
X
X#define TE_OK		0	/* No errors */
X#define TE_TWICE	1	/* Trmstart called again */
X#define TE_NOTERM	2	/* $TERM not set or empty */
X#define TE_BADTERM	3	/* $TERM not found in termcap database */
X#define TE_DUMB		4	/* Terminal too dumb */
X#define TE_NOTTY	5	/* Stdout not a tty device */
X#define TE_NOMEM	6	/* Can't get enough memory */
X#define TE_OTHER	7	/* This and higher are reserved errors */
X:>
X.fi
END_OF_FILE
if test 14015 -ne `wc -c <'Doc/vtrmdoc.ms'`; then
    echo shar: \"'Doc/vtrmdoc.ms'\" unpacked with wrong size!
fi
# end of 'Doc/vtrmdoc.ms'
fi
if test -f 'Ports/mac/scroll.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/mac/scroll.c'\"
else
echo shar: Extracting \"'Ports/mac/scroll.c'\" \(13659 characters\)
sed "s/^X//" >'Ports/mac/scroll.c' <<'END_OF_FILE'
X/* MAC STDWIN -- SCROLLING. */
X
X/* All non-public functions here assume the current grafport is set */
X
X/* XXX The contents of this file should be organized more top-down */
X
X#include "macwin.h"
X#ifdef MPW
X#include <Events.h>
X#endif
X
X/* I am using the fact here that the scroll bars of an inactive window
X   are invisible:
X   when a window's origin or its document size changes while it isn't the
X   active window, its controls get their new values but aren't redrawn. */
X
X/* Key repeat constants in low memory (set by the Control Panel),
X   in ticks (used here to control the continuous scrolling speed). */
X
X#define KeyThresh	(* (short*)0x18e)	/* Delay until repeat starts */
X#define KeyRepThresh	(* (short*)0x190)	/* Repeat rate */
X
X#define JURJENBARPROC 48 /* CDEF id for Jurjen's proportional scrollbar */
X
XSTATIC void setscrollbarvalues _ARGS((WINDOW *win));
XSTATIC void usescrollbarvalues _ARGS((WINDOW *win));
XSTATIC void sizescrollbars _ARGS((WINDOW *win));
XSTATIC void calcbar _ARGS((ControlHandle bar,
X	int org, int size, int begin, int end));
XSTATIC void setbar _ARGS((ControlHandle bar, int winsize, int val, int max));
XSTATIC void deltabar _ARGS((ControlHandle bar, int delta));
XSTATIC void showbar _ARGS((ControlHandle bar));
XSTATIC void hidebar _ARGS((ControlHandle bar));
XSTATIC void movebar _ARGS((ControlHandle bar,
X	int left, int top, int right, int bottom));
X
Xvoid
Xwsetorigin(win, orgh, orgv)
X	WINDOW *win;
X	int orgh, orgv;
X{
X	Rect r;
X	
X	/* XXX wsetorigin is currently the only routine that allows
X	   the application to show bits outside the document.
X	   Is even this desirable? */
X	
X	CLIPMIN(orgh, 0);
X	CLIPMIN(orgv, 0);
X	getwinrect(win, &r);
X	orgh -= LSLOP;
X	if (orgh != win->orgh || orgv != win->orgv) {
X		SetPort(win->w);
X		scrollby(win, &r, win->orgh - orgh, win->orgv - orgv);
X		win->orgh= orgh;
X		win->orgv= orgv;
X		setscrollbarvalues(win);
X	}
X}
X
Xvoid
Xwgetorigin(win, ph, pv)
X	WINDOW *win;
X	int *ph, *pv;
X{
X	*ph = win->orgh + LSLOP;
X	*pv = win->orgv;
X}
X
Xvoid
Xwshow(win, left, top, right, bottom)
X	WINDOW *win;
X	int left, top, right, bottom;
X{
X	int orgh, orgv;
X	int winwidth, winheight;
X	int docwidth, docheight;
X	
X	/* Calls to wshow while the mouse is down are ignored,
X	   because they tend to mess up auto-scrolling.
X	   I presume it's harmless (even the right thing to do),
X	   since wshow is usually called to make sure the object
X	   being selected is visible, which isn't a problem while
X	   the user is busy pointing at it.
X	   The check must be here, not in wsetorigin, because
X	   the latter is used internally by the auto-scroll code! */
X	if (_wm_down)
X		return;
X	
X	/* The code below is generic for all versions of stdwin */
X	
X	wgetorigin(win, &orgh, &orgv);
X	wgetwinsize(win, &winwidth, &winheight);
X	wgetdocsize(win, &docwidth, &docheight);
X	
X	orgh = calcneworigin(orgh, left, right, winwidth, docwidth);
X	orgv = calcneworigin(orgv, top, bottom, winheight, docheight);
X	
X	wsetorigin(win, orgh, orgv);
X}
X
X/* Subroutine for wshow to calculate new origin in h or v direction */
X
Xstatic int
Xcalcneworigin(org, low, high, winsize, docsize)
X	int org, low, high, winsize, docsize;
X{
X	if (docsize <= 0)
X		return org;
X	
X	/* Ignore requests to show bits outside doc */
X	/* XXX Is this necessary? */
X	CLIPMIN(low, 0);
X	CLIPMAX(high, docsize);
X	
X	/* Ignore requests for empty range */
X	/* XXX Is this what we want? */
X	if (high <= low)
X		return org;
X	
X	if (org <= low && high <= org + winsize)
X		return org;
X	
X	if (high - low > winsize) {	/* Range too big for window */
X		
X		/* Don't scroll if at least 1/3 of the window is in range */
X		/* XXX 1/3 is an arbitrary number! */
X		if (low <= org + winsize*2/3 && high >= org + winsize/3)
X			return org;
X		
X		/* Center the end of the range that's closest to the window */
X		if (low - org >= org + winsize - high) {
X			org = low - winsize/2;
X			CLIPMIN(org, 0);
X			return org;
X		}
X		else {
X			org = high - winsize/2;
X			CLIPMAX(org, docsize);
X			CLIPMIN(org, 0);
X			return org;
X		}
X	}
X	
X	/* The whole range will fit */
X	
X	/* See if it makes sense to scroll less than the window size */
X	if (low < org) {
X		if (org - low < winsize)
X			return low;
X	}
X	else if (high > org + winsize) {
X		if (high - (org + winsize) < winsize)
X			return high - winsize;
X	}
X	
X	/* Would have to scroll at least winsize -- center the range */
X	org = (low + high - winsize) / 2;
X	
X	/* Make sure we stay within the document */
X	CLIPMIN(org, 0);
X	CLIPMAX(org, docsize);
X	
X	return org;
X}
X
Xvoid
Xwsetdocsize(win, docwidth, docheight)
X	WINDOW *win;
X	int docwidth, docheight;
X{
X	CLIPMIN(docwidth, 0);
X	CLIPMIN(docheight, 0);
X	if (docwidth == win->docwidth && docheight == win->docheight)
X		return;
X	win->docwidth= docwidth;
X	win->docheight= docheight;
X	SetPort(win->w);
X	setscrollbarvalues(win);
X	_wfixorigin(win);
X	
X	/* Make the zoomed window size the full document size,
X	   or the full screen size if the document is bigger. */
X	
X	if (((WindowPeek)(win->w))->dataHandle != NULL) {
X		WStateData *data = (WStateData *)
X			*((WindowPeek)(win->w))->dataHandle;
X		if (data != NULL) {
X			if (docwidth > 0) {
X				CLIPMIN(docwidth, MIN_WIDTH);
X				data->stdState.right =
X					data->stdState.left
X					+ LSLOP + docwidth + RSLOP + BAR;
X			}
X			else
X				data->stdState.right = 0x7fff;
X			CLIPMAX(data->stdState.right,
X				screen->portRect.right-3);
X			if (docheight > 0) {
X				CLIPMIN(docheight, MIN_HEIGHT);
X				data->stdState.bottom =
X					data->stdState.top
X					+ docheight + BAR;
X			}
X			else
X				data->stdState.bottom = 0x7fff;
X			CLIPMAX(data->stdState.bottom,
X				screen->portRect.bottom-3);
X		}
X	}
X}
X
Xvoid
Xwgetdocsize(win, pwidth, pheight)
X	WINDOW *win;
X	int *pwidth, *pheight;
X{
X	*pwidth = win->docwidth;
X	*pheight = win->docheight;
X}
X
X/* Fix the window's origin after a document or window resize.
X   (Also used from do_size() in event.c) */
X
X_wfixorigin(win)
X	WINDOW *win;
X{
X	int orgh, orgv;
X	int winwidth, winheight;
X	int docwidth, docheight;
X	wgetorigin(win, &orgh, &orgv);
X	wgetwinsize(win, &winwidth, &winheight);
X	wgetdocsize(win, &docwidth, &docheight);
X	
X	/* XXX Do we really want this?
X	   This means that in a text edit window, if you are focused
X	   at the bottom, every line deletion causes a scroll.
X	   Oh well, I suppose that text edit windows could fix
X	   their document size to include some blank lines at the
X	   end...
X	*/
X	
X	CLIPMAX(orgh, docwidth - winwidth);
X	CLIPMIN(orgh, 0);
X	CLIPMAX(orgv, docheight - winheight);
X	CLIPMIN(orgv, 0);
X	wsetorigin(win, orgh, orgv);
X}
X
X/* do_scroll is called from event.c when a click in a scroll bar
X   is detected */
X
XSTATIC pascal trackbar(ControlHandle bar, short pcode); /* Forward */
X
Xstatic WINDOW *scrollwin;	/* The window (needed by 'trackbar') */
Xstatic int scrollstep;		/* By how much we scroll */
Xstatic long deadline;		/* When the next step may happen */
X
Xvoid
Xdo_scroll(pwhere, win, bar, pcode)
X	Point *pwhere;
X	WINDOW *win;
X	ControlHandle bar;
X	int pcode;
X{
X	int step, page;
X	ProcPtr action;
X	int width, height;
X	
X	wgetwinsize(win, &width, &height);
X	
X	if (bar == win->hbar) {
X		step= width / 20;
X		CLIPMIN(step, 1);
X		page= width / 2;
X	}
X	else if (bar == win->vbar) {
X		step= wlineheight(); /* Should use current win's */
X		page= height - step;
X	}
X	else
X		return;
X	
X	page= (page/step) * step; /* Round down to multiple of step */
X	action= trackbar;
X	scrollwin= win;
X	
X	switch (pcode) {
X	case inUpButton:
X		scrollstep= -step;
X		break;
X	case inDownButton:
X		scrollstep= step;
X		break;
X	case inPageUp:
X		scrollstep= -page;
X		break;
X	case inPageDown:
X		scrollstep= page;
X		break;
X	default:
X		action= NULL;
X		break;
X	}
X	
X	deadline= 0;
X	if (TrackControl(bar, PASSPOINT *pwhere, action) == inThumb)
X		usescrollbarvalues(win);
X}
X
Xstatic pascal
Xtrackbar(bar, pcode)
X	ControlHandle bar;
X	short pcode;
X{
X	long now= TickCount();
X	if (now >= deadline && pcode != 0) {
X		deltabar(bar, scrollstep);
X		usescrollbarvalues(scrollwin);
X		wupdate(scrollwin);
X		if (deadline == 0 && KeyThresh > KeyRepThresh)
X			deadline= now + KeyThresh;
X			/* Longer delay first time */
X		else
X			deadline= now + KeyRepThresh;
X	}
X}
X
X/* Automatic scrolling when the mouse is pressed and moved outside
X   the application panel. */
X
Xvoid
Xautoscroll(win, h, v)
X	WINDOW *win;
X	int h, v; /* Mouse location in local coordinates */
X{
X	Rect r;
X	int dh= 0, dv= 0;
X	
X	getwinrect(win, &r);
X	if (h < r.left)
X		dh= h - r.left;
X	else if (h > r.right)
X		dh= h - r.right;
X	if (v < r.top)
X		dv= v - r.top;
X	else if (v > r.bottom)
X		dv= v - r.bottom;
X	if (dh != 0 || dv != 0) {
X		/* NOTE: assuming current grafport is win->w */
X		deltabar(win->hbar, dh);
X		deltabar(win->vbar, dv);
X		usescrollbarvalues(win);
X	}
X}
X
X/* Alternative scrolling: Option-click produces a 'hand' cursor
X   and allows scrolling like in MacPaint.  Called from event.c. */
X
Xvoid
Xdragscroll(win, h, v, constrained)
X	WINDOW *win;
X	int h, v;
X	int constrained;
X{
X	int do_h= !constrained, do_v= !constrained;
X	
X	while (StillDown()) {
X		Point mouse;
X		SetPort(win->w);
X		GetMouse(&mouse);
X		if (constrained) {
X			int ah= ABS(h - mouse.h);
X			int av= ABS(v - mouse.v);
X			if (ABS(ah - av) < 2)
X				continue;
X			if (ah > av)
X				do_h= TRUE;
X			else
X				do_v= TRUE;
X			constrained= FALSE;
X		}
X		if (do_h)
X			deltabar(win->hbar, h - mouse.h);
X		if (do_v)
X			deltabar(win->vbar, v - mouse.v);
X		usescrollbarvalues(win);
X		wupdate(win);
X		h= mouse.h;
X		v= mouse.v;
X	}
X}
X
Xvoid
Xmakescrollbars(win)
X	WINDOW *win;
X{
X	Rect r;
X	int id= scrollBarProc;
X	
X	/* The scroll bars are initially created at a dummy location,
X	   and then moved to their proper location.
X	   They are not displayed here;
X	   that's done only when an activate event arrives. */
X	
X#ifdef JURJENBARPROC
X	/* If Jurjen's proportional scroll bar exists, use it.
X	   (For the vertical bar only -- it doesn't understand
X	   about horizontal bars...) */
X	if (cdefexists(JURJENBARPROC))
X		id= JURJENBARPROC;
X#endif JURJENBARPROC
X
X	SetRect(&r, 0, 0, 1, 1); /* Dummy rectangle */
X	win->hbar= NewControl(win->w,
X		&r, "", false, 0, 0, 0, scrollBarProc, 0L);
X	win->vbar= NewControl(win->w,
X		&r, "", false, 0, 0, 0, id, 0L);
X	sizescrollbars(win);
X}
X
X#ifdef JURJENBARPROC
Xstatic int
Xcdefexists(id)
X	int id;
X{
X	return GetResource('CDEF', id/16) != NULL;
X}
X#endif
X
Xvoid
Xshowscrollbars(win)
X	WINDOW *win;
X{
X	DrawGrowIcon(win->w);
X	showbar(win->hbar);
X	showbar(win->vbar);
X}
X
Xvoid
Xhidescrollbars(win)
X	WINDOW *win;
X{
X	hidebar(win->hbar);
X	hidebar(win->vbar);
X}
X
Xvoid
Xmovescrollbars(win)
X	WINDOW *win;
X{
X	hidescrollbars(win);
X	sizescrollbars(win);
X	showscrollbars(win);
X}
X
Xstatic void
Xsizescrollbars(win)
X	WINDOW *win;
X{
X	Rect r;
X	
X	/* This should be done while the scroll bars are invisible. */
X	
X	r= win->w->portRect;
X	movebar(win->vbar, r.right - BAR, r.top - 1,
X		r.right + 1, r.bottom - BAR + 1);
X	movebar(win->hbar, r.left - 1, r.bottom - BAR,
X		r.right - BAR + 1, r.bottom + 1);
X	setscrollbarvalues(win);
X}
X
Xstatic void
Xsetscrollbarvalues(win)
X	WINDOW *win;
X{
X	Rect r;
X	
X	getwinrect(win, &r);
X	calcbar(win->hbar,
X		win->orgh, win->docwidth, LSLOP, r.right - r.left - RSLOP);
X	calcbar(win->vbar,
X		win->orgv, win->docheight, 0, r.bottom - r.top);
X	if (win == active) {
X		/* XXX Should only draw those controls that have changed. */
X		DrawControls(win->w);
X		valid_border(win->w);
X	}
X}
X
X/*
X * Calculate (and set!) the new value of a scroll bar.
X * Parameters (all pertaining to either h or v): 
X * org: 	origin of window (win->orgh or win->orgv)
X * size:	extent of document (win->docwidth or win->docheight)
X * begin:	position of document origin if bar is at its beginning
X * end:		position of document end if bar is at its end
X * Situation sketch:
X *                0    begin                          end  winwidth
X *                +====+==============================+====+
X *                     +--------------------------------------------------+
X * +--------------------------------------------------+
X * Window shown on top; min document position in the middle;
X * max document position below.  Org is (begin of win) - (begin of doc).
X */
X
Xstatic void
Xcalcbar(bar, org, size, begin, end)
X	ControlHandle bar;
X	int org, size;
X	int begin, end;
X{
X	int range;
X	/* For the caller it's easier to remember to pass win->org{h,v};
X	   but for our calculations it's easier to have the sign reversed! */
X	org= -org;
X	CLIPMIN(begin, org);
X	CLIPMIN(size, 0);
X	CLIPMAX(end, org + size);
X	range = size - (end - begin);
X	CLIPMIN(range, 0);
X	setbar(bar, end - begin, begin - org, range);
X}
X
Xstatic void
Xusescrollbarvalues(win)
X	WINDOW *win;
X{
X	wsetorigin(win,
X		GetCtlValue(win->hbar) - GetCtlMin(win->hbar),
X		GetCtlValue(win->vbar) - GetCtlMin(win->vbar));
X	/* Implies setscrollbarvalues! */
X}
X
Xstatic void
Xsetbar(bar, winsize, val, max)
X	ControlHandle bar;
X	int winsize, val, max;
X{
X	if (bar != NULL) {
X		ControlPtr p= *bar;
X		if (max < 0)
X			max= 0;
X		if (val > max)
X			val= max;
X		if (val < 0)
X			val= 0;
X		p->contrlMin= winsize;
X		p->contrlValue= val + winsize;
X		p->contrlMax= max + winsize;
X		/* Must be drawn by DrawControls or ShowControl. */
X	}
X}
X
Xstatic void
Xdeltabar(bar, delta)
X	ControlHandle bar;
X	int delta;
X{
X	int min= GetCtlMin(bar);
X	int val= GetCtlValue(bar);
X	int max= GetCtlMax(bar);
X	int newval= val + delta;
X	
X	if (newval > max)
X		newval= max;
X	if (newval < min)
X		newval= min;
X	if (newval != val)
X		SetCtlValue(bar, newval);
X}
X
Xstatic void
Xshowbar(bar)
X	ControlHandle bar;
X{
X	if (bar != NULL)
X		ShowControl(bar);
X}
X
Xstatic void
Xhidebar(bar)
X	ControlHandle bar;
X{
X	if (bar != NULL)
X		HideControl(bar);
X}
X
Xstatic void
Xmovebar(bar, left, top, right, bottom)
X	ControlHandle bar;
X	int left, top, right, bottom;
X{
X	if (bar != NULL) {
X		/* This works best while the scroll bar is invisible. */
X		MoveControl(bar, left, top);
X		SizeControl(bar, right-left, bottom-top);
X	}
X}
END_OF_FILE
if test 13659 -ne `wc -c <'Ports/mac/scroll.c'`; then
    echo shar: \"'Ports/mac/scroll.c'\" unpacked with wrong size!
fi
# end of 'Ports/mac/scroll.c'
fi
if test -f 'Ports/x11/general.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/x11/general.c'\"
else
echo shar: Extracting \"'Ports/x11/general.c'\" \(13917 characters\)
sed "s/^X//" >'Ports/x11/general.c' <<'END_OF_FILE'
X/* X11 STDWIN -- General initializations, enquiries and defaults */
X
X#include "x11.h"
X
X
X/* Private globals */
X
XDisplay *_wd;			/* The Display (== connection) */
XScreen *_ws;			/* The screen */
XXFontStruct *_wf;		/* The font */
XXFontStruct *_wmf;		/* The menu font */
X#ifdef PIPEHACK
Xint _wpipe[2];			/* Pipe used by wungetevent from handler */
X#endif
X#ifdef AMOEBA
X#include <amoeba.h>
X#include <semaphore.h>
Xextern semaphore *_wsema;	/* From amtimer.c */
X#endif
Xchar *_wprogname = "stdwin";	/* Program name from argv[0] */
Xstatic char *_wdisplayname;	/* Display name */
X
X/* Interned atoms */
X
XAtom _wm_protocols;
XAtom _wm_delete_window;
XAtom _wm_take_focus;
X
X/* Globals used to communicate hints to wopen() */
X
Xchar *_whostname;
Xchar *_wm_command;
Xint _wm_command_len;
X
X/* Copy the arguments away to _wm_command, and get the host name */
X
Xstatic void
Xstoreargcargv(argc, argv)
X	int argc;
X	char **argv;
X{
X	int i;
X	char *bp;
X	char buf[256];
X	
X	/* Calculate length of buffer to allocate */
X	_wm_command_len= 0;
X	for (i= 0; i < argc; i++)
X		_wm_command_len += strlen(argv[i]) + 1;
X	if (_wm_command_len != 0) {
X		_wm_command= bp= malloc((unsigned)_wm_command_len);
X		for (i= 0; i < argc; i++) {
X			strcpy(bp, argv[i]);
X			bp += strlen(argv[i]) + 1;
X		}
X	}
X	
X	buf[0]= EOS;
X	gethostname(buf, sizeof buf);
X	buf[(sizeof buf)-1]= EOS;
X	_whostname= strdup(buf);
X}
X
X/* Function to get a default directly from a database */
X
Xstatic char *
Xgetoption(db, name, classname)
X	XrmDatabase db;
X	char *name;
X	char *classname;
X{
X	char namebuf[256], classnamebuf[256];
X	char *type;
X	XrmValue rmvalue;
X	
X	sprintf(namebuf, "%s.%s", _wprogname, name);
X	sprintf(classnamebuf, "Stdwin.%s", classname);
X	if (XrmGetResource(db, namebuf, classnamebuf, &type, &rmvalue))
X		return rmvalue.addr;
X	else
X		return NULL;
X}
X
X/* Command line options tables */
X
X/* NOTE: To prevent stdwin eating user options scanned with getopt(3),
X   single-letter options must never be acceptable as abbreviations.
X   When necessary, this is ensured by adding dummy options, e.g., "-g:"
X   because there is only one option starting with "-g" ("-geometry").
X   (The colon is used as second character because getopt() uses it as a
X   delimiter.)
X   Watch out: if you remove the last option starting with a certain
X   letter, also remove the dummy option!
X*/
X
X/* Table 1: command-line only options */
X
Xstatic XrmOptionDescRec options1[]= {
X  
X{"-debuglevel",		".debugLevel",		XrmoptionSepArg, NULL},
X{"-display",		".display",		XrmoptionSepArg, NULL},
X
X{"-n:",			NULL,			XrmoptionIsArg,  NULL},
X{"-name",		".name",		XrmoptionSepArg, NULL},
X
X{"-s:",			NULL,			XrmoptionIsArg,  NULL},
X{"-synchronous",	".synchronous",		XrmoptionNoArg,  "on"},
X
X};
X
X/* Table 2: options to be merged with resources */
X
Xstatic XrmOptionDescRec options2[]= {
X
X/* Command line options to override resources.
X   All the options named in "man X" are supported, except those to
X   do with borders (-bd, -bw) or national language choice (-xnl*). */
X
X{"-background",		".background",		XrmoptionSepArg, NULL},
X{"-bg",			".background",		XrmoptionSepArg, NULL},
X
X{"-font",		".font",		XrmoptionSepArg, NULL},
X{"-fn",			".font",		XrmoptionSepArg, NULL},
X{"-foreground",		".foreground",		XrmoptionSepArg, NULL},
X{"-fg",			".foreground",		XrmoptionSepArg, NULL},
X
X{"-g:",			NULL,			XrmoptionIsArg,  NULL},
X{"-geometry",		".geometry",		XrmoptionSepArg, NULL},
X
X{"-iconic",		".iconic",		XrmoptionNoArg,  "on"},
X{"-iconbitmap",		".iconBitmap",		XrmoptionSepArg, NULL},
X{"-icongeometry",	".iconGeometry",	XrmoptionSepArg, NULL},
X{"-iconmask",		".iconMask",		XrmoptionSepArg, NULL},
X
X{"-menubackground",	".menuBackground",	XrmoptionSepArg, NULL},
X{"-menufont",		".menuFont",		XrmoptionSepArg, NULL},
X{"-menufn",		".menuFont",		XrmoptionSepArg, NULL},
X{"-menuforeground",	".menuForeground",	XrmoptionSepArg, NULL},
X
X{"-reversevideo",	".reverse",		XrmoptionNoArg,  "on"},
X{"-rv",			".reverse",		XrmoptionNoArg,  "on"},
X{"+rv",			".reverse",		XrmoptionNoArg,  "off"},
X
X{"-s:",			NULL,			XrmoptionIsArg,  NULL},
X{"-selectionTimeout",	".selectionTimeout",	XrmoptionSepArg, NULL},
X
X{"-t:",			NULL,			XrmoptionIsArg,  NULL},
X{"-title",		".title",		XrmoptionSepArg, NULL},
X
X{"-x:",			NULL,			XrmoptionIsArg,  NULL},
X{"-xrm",		NULL,			XrmoptionResArg, NULL},
X
X/* Options that end option processing completely:
X   "-" means <stdin>, "--" is a getopt(3) convention
X   to force the end of the option list. */
X
X{"-",			NULL,			XrmoptionSkipLine, NULL},
X{"--",			NULL,			XrmoptionSkipLine, NULL},
X
X};
X
X#define NUM(options) (sizeof options / sizeof options[0])
X
X
X/* Initialization is split in two parts -- wargs(&argc, &argv) to process
X   the command line, winit() to open the connection.  The call
X   winitargs(&argc, &argv) calls wargs() and then winit().
X
X   Programs that call winit() without callin wargs() will always
X   appear to have the name "stdwin", and you can't pass X command
X   line arguments on their command line.  Defaults put in the server's
X   resource database for application name 'stdwin' will work, though.
X   You can also set the environment variable RESOURCE_NAME. */
X
X
Xstatic XrmDatabase db = NULL; /* Passed between wargs() and winit() */
Xstatic int wargs_called; /* Set when wargs is called */
X
X/* Part one of the initialization -- process command line arguments */
X
Xvoid
Xwargs(pargc, pargv)
X	int *pargc;
X	char ***pargv;
X{
X	char **argv= *pargv;
X	char *value;
X	
X	if (wargs_called)
X		_wfatal("wargs: called more than once");
X	wargs_called = 1;
X	
X	/* Get the program name (similar to basename(argv[0])) */
X	
X	if (*pargc > 0 && argv[0] != NULL && argv[0][0] != EOS) {
X		_wprogname= strrchr(argv[0], '/');
X		if (_wprogname != NULL && _wprogname[1] != EOS)
X			++_wprogname;
X		else
X			_wprogname= argv[0];
X	}
X	
X	/* Save entire argument list for WM_COMMAND hint; plus hostname */
X	
X	storeargcargv(*pargc, argv);
X	
X	/* Get command-line-only X options */
X	
X	XrmParseCommand(&db, options1, NUM(options1),
X		_wprogname, pargc, *pargv);
X	
X	/* Get -debuglevel argument from temp database.
X	   This is done first so calls to _wdebug will work. */
X	
X	if ((value= getoption(db, "debugLevel", "DebugLevel")) != NULL) {
X		_wtracelevel= _wdebuglevel= atoi(value);
X		setlinebuf(stderr);
X		_wwarning("wargs: -debuglevel %d", _wdebuglevel, value);
X	}
X	
X	/* Get -display argument from temp database */
X	
X	if ((_wdisplayname= getoption(db, "display", "Display")) != NULL)
X		_wdebug(1, "wargs: -display %s", _wdisplayname);
X	
X	/* Get -name argument from temp database.
X	   This will override the command name used by _wgetdefault.
X	   You can use this to pretend the command name is different,
X	   so it gets its options from a different part of the defaults
X	   database.  (Try -name xmh. :-)
X	   If -name is not set, getenv("RESOURCE_NAME") will override
X	   _wprogname (if non-empty). */
X	
X	if ((value= getoption(db, "name", "Name")) != NULL) {
X		_wdebug(1, "wargs: -name %s", value);
X		_wprogname= strdup(value);
X	}
X	else if ((value = getenv("RESOURCE_NAME")) != NULL && *value != '\0') {
X		_wdebug(1, "wargs: RESOURCE_NAME=%s", value);
X		_wprogname = strdup(value);
X	}
X	
X	/* Get the remaining command line options.
X	   Option parsing is done in two phases so that if the user
X	   specifies -name and -geometry, the geometry is stored under
X	   the new name (else it won't be found by _wgetdefault later). */
X	
X	XrmParseCommand(&db, options2, NUM(options2),
X		_wprogname, pargc, *pargv);
X}
X
X
X/* Part two of the initialization -- open the display */
X
Xvoid
Xwinit()
X{
X	char *value;
X
X	/* Call wargs() with dummy arguments if not already called */
X
X	if (!wargs_called) {
X		static char* def_args[]= {"stdwin", (char*)NULL};
X		int argc= 1;
X		char **argv= def_args;
X		wargs(&argc, &argv);
X	}
X	
X	/* Open the display, die if we can't */
X	
X	_wd= XOpenDisplay(_wdisplayname);
X	if (_wd == NULL) {
X		_wfatal("winit: can't open display (%s)",
X			_wdisplayname ? _wdisplayname :
X			getenv("DISPLAY") ? getenv("DISPLAY") : "<none>");
X	}
X	
X#ifdef AMOEBA
X	/* Set the semaphore.  This must be done before doing anything
X	   else with the connection. */
X	if (_wsema != NULL)
X		XamSetSema(_wd, _wsema);
X#endif
X	
X	/* Turn on synchronous mode if required.
X	   This is not automatic when debuglevel is set,
X	   since some bugs disappear in synchronous mode! */
X	
X	if (getoption(db, "synchronous", "Synchronous") != NULL)
X		XSynchronize(_wd, True);
X	
X	/* Call XGetDefault() once.  We don't use it to get our
X	   defaults, since it doesn't let the caller specify the class
X	   name for the resource requested, but the first call to it
X	   also initializes the resources database from various sources
X	   following conventions defined by the X toolkit, and that code
X	   is too convoluted (and X11-version specific?) to bother to
X	   repeat it here. */
X	
X	(void) XGetDefault(_wd, _wprogname, "unused");
X	
X	/* From now on, use _wgetdefault() exclusively to get defaults */
X	
X	/* Get the debug level again, this time from the user's
X	   defaults database.  This value overrides only if larger. */
X	
X	value= _wgetdefault("debugLevel", "DebugLevel");
X	if (value != 0) {
X		int k= atoi(value);
X		if (k > _wdebuglevel) {
X			_wtracelevel= _wdebuglevel= k;
X			_wdebug(1, "winit: new debuglevel %d (%s)",
X				_wdebuglevel, value);
X			XSynchronize(_wd, True);
X		}
X	}
X	
X	/* Merge the command line options with the defaults database.
X	   This must be done after the call to XGetDefault (above),
X	   otherwise XGetDefault doesn't care to load the database.
X	   I assume that the command line options get higher priority
X	   than the user defaults in this way. */
X	
X	XrmMergeDatabases(db, &_wd->db);
X	db = NULL;
X	
X	/* Get the default screen (the only one we use) */
X	
X	_ws= DefaultScreenOfDisplay(_wd);
X	
X	_wdebug(1, "server does%s save-unders",
X		DoesSaveUnders(_ws) ? "" : "n't do");
X	
X	/* Intern some atoms (unconditionally) */
X	
X	_wm_protocols = XInternAtom(_wd, "WM_PROTOCOLS", False);
X	_wm_delete_window = XInternAtom(_wd, "WM_DELETE_WINDOW", False);
X	_wm_take_focus = XInternAtom(_wd, "WM_TAKE_FOCUS", False);
X	
X	/* Initialize font list */
X	
X	_winitfonts();
X	
X#ifdef PIPEHACK
X	/* Create the pipe used to communicate wungetevent calls
X	   from a signal handler to wgetevent */
X	
X	if (pipe(_wpipe) != 0) {
X		_wwarning("winit: can't create pipe");
X		_wpipe[0]= _wpipe[1]= -1;
X	}
X#endif
X}
X
X
X/* Call both parts of the initialization together */
X
Xvoid
Xwinitargs(pargc, pargv)
X	int *pargc;
X	char ***pargv;
X{
X	wargs(pargc, pargv);
X	winit();
X}
X
X
X/* Return the name of the display, if known.  (X11 stdwin only.) */
X
Xchar *
Xwdisplayname()
X{
X	return _wdisplayname ? _wdisplayname : getenv("DISPLAY");
X}
X
X
X/* Clean up */
X
Xvoid
Xwdone()
X{
X	/* This may be called when we are not initialized */
X	if (_wd) {
X		_wkillwindows();
X		_wkillmenus();
X		XFlush(_wd); /* Show possibly queued visual effects */
X		XCloseDisplay(_wd);
X		_wd = NULL;
X	}
X}
X
X/* Flush server queue */
X
Xvoid
Xwflush()
X{
X	XFlush(_wd);
X}
X
X
X/* Get screen size */
X
Xvoid
Xwgetscrsize(pwidth, pheight)
X	int *pwidth, *pheight;
X{
X	*pwidth= WidthOfScreen(_ws);
X	*pheight= HeightOfScreen(_ws);
X}
X
X
X/* Get screen size in mm */
X
Xvoid
Xwgetscrmm(pwidth, pheight)
X	int *pwidth, *pheight;
X{
X	*pwidth= WidthMMOfScreen(_ws);
X	*pheight= HeightMMOfScreen(_ws);
X}
X
X/* Subroutine to invert a rectangle.
X   On a colour display, we invert all planes that have a different
X   value in the foreground and background pixels, thus swapping
X   fg anbd bg colors.
X   Since we can't get the fg and bg pixels from a GC without cheating
X   (i.e., risking future incompatibility), we depend on the fact
X   that the plane mask is *always* set to the XOR of the fg and bg colors.
X   If the bg color for the window is the same as the bg for the GC,
X   this means all draw operations need only be concerned with those planes.
X*/
X
X_winvert(d, gc, x, y, width, height)
X	Drawable d;
X	GC gc;
X	int x, y, width, height;
X{
X	XSetFunction(_wd, gc, GXinvert);
X	XFillRectangle(_wd, d, gc, x, y, width, height);
X	XSetFunction(_wd, gc, GXcopy);
X}
X
X/* Get a default (replaces XGetDefault calls) */
X
X#include <ctype.h>
X
Xchar *
X_wgetdefault(name, classname)
X	char *name;
X	char *classname;
X{
X	char namebuf[256], classnamebuf[256];
X	register char *p;
X	
X	p = getoption(_wd->db, name, classname);
X	if (p != NULL)
X		return p;
X	
X	/* XXX Compatibility hack.  Previous versions of STDWIN used
X	   a different resource format, where the name would be
X	   <progname>.stdwin.<resname> and the classname was defaulted
X	   by XGetDefault to Program.Name (or some such).
X	   The resource names were also all lowercase. */
X	sprintf(namebuf, "stdwin.%s", name);
X	sprintf(classnamebuf, "Stdwin.%s", classname);
X	for (p = namebuf; *p != '\0'; p++) {
X		if (isupper(*p))
X			*p = tolower(*p);
X	}
X	_wdebug(1, "_wgetdefault(%s, %s): no luck, trying %s, %s",
X		name, classname, namebuf, classnamebuf);
X	return getoption(_wd->db, namebuf, classnamebuf);
X}
X
X/* Get a Boolean default.  May be 'on' or 'off', 'true' or 'false',
X   '1' or '0'.  If not present, return the default value. */
X
Xint
X_wgetbool(name, classname, def)
X	char *name;
X	char *classname;
X	int def;
X{
X	register char *value;
X	static struct flags {
X		char *name;
X		int value;
X	};
X	static struct flags flags[] = {
X		{"on",		1},
X		{"true",	1},
X		{"yes",		1},
X		{"1",		1},
X		
X		{"off",		0},
X		{"false",	0},
X		{"no",		0},
X		{"0",		0},
X		
X		{NULL,		0}	/* Sentinel */
X	};
X	struct flags *fp, *hit;
X	
X	value = _wgetdefault(name, classname);
X	if (value == NULL)
X		return def;
X	hit = NULL;
X	for (fp = flags; fp->name != NULL; fp++) {
X		if (matchname(fp->name, value)) {
X			if (hit != NULL)
X				_wwarning(
X				    "ambiguous resource value for %s: %s",
X				    name, value);
X			hit = fp;
X		}
X	}
X	if (hit != NULL)
X		def = hit->value;
X	else
X		_wwarning("unknown resource value for %s: %s", name, value);
X	return def;
X}
X
Xstatic int
Xmatchname(fullname, shortname)
X	char *fullname;
X	char *shortname;
X{
X	register int c;
X	while ((c = *shortname++) != '\0') {
X		if (isupper(c))
X			c = tolower(c);
X		if (c != *fullname++)
X			return 0;
X	}
X	return 1;
X}
END_OF_FILE
if test 13917 -ne `wc -c <'Ports/x11/general.c'`; then
    echo shar: \"'Ports/x11/general.c'\" unpacked with wrong size!
fi
# end of 'Ports/x11/general.c'
fi
if test -f 'Ports/x11/llevent.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/x11/llevent.c'\"
else
echo shar: Extracting \"'Ports/x11/llevent.c'\" \(8971 characters\)
sed "s/^X//" >'Ports/x11/llevent.c' <<'END_OF_FILE'
X/* X11 STDWIN -- Low-level event handling */
X
X#include "x11.h"
X#include "llevent.h"
X#include <X11/keysym.h>
X
X/* Double-click detection parameters */
X
X#define DCLICKTIME	500
X#define DCLICKDIST	5
X
X/* Events are handled in two phases.
X   There is low-level event handling which can be called at any time
X   and will only set various flags (global and in windows) indicating
X   changed circumstances.  This kind of event handling goes on even
X   while we are locked in a dialog box.
X   There is high-level event handling which passes the results of the
X   low-level handling to the application in request to a call to
X   'wgetevent'.
X   This file contains the low-level event handling. */
X
X
X/* Low-level event handler.
X   Data items set for use by higher-level event handler include:
X   
X   - the 'new active window' pointer
X   - the 'dirty' flags for all windows and subwindows
X   - the 'size changed' flags for all top-level windows
X   
X   These can be accumulated; the net effect of all such events is
X   correctly remembered.  The following data items are also set but need
X   to be checked after each call, since they are not queued:
X   
X   - the mouse button state
X   - the 'last-key-pressed' variable
X   
X   Mouse moves may be ignored, however.
X   The state change flags must be be reset by the higher-level event
X   handler after the changes have been noted. */
X
XWINDOW *_w_new_active;		/* New active window */
Xstruct button_state _w_bs;	/* Mouse button state */
XKeySym _w_keysym;		/* Keysym of last non-modifier key pressed */
Xint _w_state;			/* Modifiers in effect at key press */
X
Xbool _w_moved;			/* Set if button moved */
Xbool _w_bs_changed;		/* Set if button up/down state changed */
Xbool _w_dirty;			/* Set if any window needs a redraw */
Xbool _w_resized;		/* Set if any window resized */
Xbool _w_focused;		/* Set if between FocusIn and FocusOut */
XTime _w_lasttime = CurrentTime;	/* Last timestamp received in an event */
XWINDOW *_w_close_this;		/* Window to close (WM_DELETE_WINDOW) */
X
X_w_ll_event(e)
X	XEvent *e;
X{
X	WINDOW *win;
X	
X	_wdebug(6, "_w_ll_event: event type %ld", e->type);
X	
X	win = _whichwin(e->xkey.window);
X	if (win == NULL) {
X		_wdebug(6, "_w_ll_event: event not for any window -- ignore");
X		return;
X	}
X	
X	switch (e->type) {
X	
X	/* Keyboard */
X	
X	case KeyPress:
X		_w_lasttime = e->xkey.time;
X		activate(win);
X		ll_key(&e->xkey, win);
X		break;
X	
X	case MappingNotify:
X		XRefreshKeyboardMapping(&e->xmapping);
X		break;
X	
X	/* Buttons */
X	
X	case MotionNotify:
X#ifndef DONT_COMPRESS_MOTION /* XXX should be a resource option instead */
X		/* Compress motion events */
X		while (XPending(_wd) > 0) {
X			XEvent e2;
X			XPeekEvent(_wd, &e2);
X			if (e2.type == MotionNotify &&
X				e2.xmotion.window == e->xmotion.window &&
X				e2.xmotion.subwindow == e->xmotion.subwindow) {
X				/* replace current event with next one */
X				XNextEvent(_wd, e);
X			}
X			else
X				break;
X		}
X#endif
X		/* Fall through */
X	case ButtonPress:
X	case ButtonRelease:
X		_w_lasttime = e->xbutton.time;
X		ll_button(&e->xbutton, win);
X		break;
X	
X	/* Exposures */
X	
X	case GraphicsExpose:
X		_wdebug(3, "GraphicsExpose event:");
X	case Expose:
X		ll_expose(&e->xexpose, win);
X		break;
X	
X	/* Structure changes */
X	
X	case ConfigureNotify:
X		ll_configure(&e->xconfigure, win);
X		break;
X	
X	/* Input focus changes */
X	
X	case FocusIn:
X		_w_focused= TRUE;
X		activate(win);
X		break;
X	
X	case FocusOut:
X		_w_focused= FALSE;
X		deactivate(win);
X		break;
X	
X	case EnterNotify:
X		_w_lasttime = e->xcrossing.time;
X		if (!_w_focused && e->xcrossing.focus)
X			activate(win);
X		break;
X	
X	case LeaveNotify:
X		_w_lasttime = e->xcrossing.time;
X		if (!_w_focused && e->xcrossing.detail != NotifyInferior &&
X				e->xcrossing.focus)
X			deactivate(win);
X		break;
X	
X	/* ICCCM */
X	
X	case ClientMessage:
X		_wdebug(2,
X			"ClientMessage, type=%ld, send_event=%ld, format=%ld",
X			e->xclient.message_type,
X			e->xclient.send_event,
X			e->xclient.format);
X		if (e->xclient.message_type == _wm_protocols) {
X			_wdebug(2, "It's a WM_PROTOCOLS ClientMessage (%ld)",
X				e->xclient.data.l[0]);
X			_w_lasttime = e->xclient.data.l[1];
X		}
X		else {
X			_wdebug(1, "Unexpected ClientMessage ignored (%ld)",
X				e->xclient.message_type);
X			break;
X		}
X		if (e->xclient.data.l[0] == _wm_delete_window) {
X			_wdebug(1, "WM_DELETE_WINDOW");
X			_w_close_this = win;
X		}
X		else {
X			_wdebug(1,
X				"Unexpected WM_PROTOCOLS ClientMessage (%ld)",
X				e->xclient.data.l[0]);
X		}
X		break;
X	
X	case SelectionRequest:
X		_w_selectionreply(
X			e->xselectionrequest.owner,
X			e->xselectionrequest.requestor,
X			e->xselectionrequest.selection,
X			e->xselectionrequest.target,
X			e->xselectionrequest.property,
X			e->xselectionrequest.time);
X		break;
X	
X	case SelectionClear:
X		_w_selectionclear(e->xselectionclear.selection);
X		break;
X	
X	case MapNotify:
X		/* Ignore this */
X		break;
X	
X	default:
X		_wdebug(1, "unexpected event type %d", e->type);
X	
X	}
X}
X
Xstatic
Xactivate(win)
X	WINDOW *win;
X{
X	if (_w_new_active != win) {
X		if (_w_new_active != NULL)
X			deactivate(_w_new_active);
X		_w_new_active= win;
X		if (win != NULL)
X			XSetWindowBorder(_wd, win->wo.wid, win->fgo);
X	}
X}
X
Xstatic
Xdeactivate(win)
X	WINDOW *win;
X{
X	if (win == _w_new_active) {
X		_w_new_active= NULL;
X		if (win != NULL)
X			_w_setgrayborder(win);
X	}
X}
X
Xstatic
Xll_key(e, win)
X	XKeyEvent *e;
X	WINDOW *win;
X{
X	char sbuf[1];
X	
X	_wdebug(6, "keycode %d, state 0x%x", e->keycode, e->state);
X	if (XLookupString(e, sbuf, 1, &_w_keysym, (XComposeStatus*)NULL) > 0)
X		_w_keysym= sbuf[0];
X	else if (IsModifierKey(_w_keysym))
X		_w_keysym= 0;
X	_w_state= e->state;
X}
X
X/* Update button status, given a Button or Motion event.
X   THIS ASSUMES BUTTON AND MOTION EVENTS HAVE THE SAME LAY-OUT! */
X
Xstatic
Xll_button(e, win)
X	XButtonEvent *e;
X	WINDOW *win;
X{
X	Window w= e->window;
X	
X	/* This code is ugly.  I know. */
X	
X	if (!_w_bs.down) { /* New sequence */
X		if (e->type != ButtonPress) {
X			/* Button moved/release event while we've never
X			   received a corresponding press event.
X			   I suspect this is a server bug;
X			   normally I never reach this code, but sometimes
X			   it happens continually.  Why?... */
X			_wdebug(5,
X				"ll_button: spurious button move/release %d",
X				e->type);
X			return;
X		}
X		else {
X			bool isdclick= FALSE;
X			_w_bs.down= TRUE;
X			_w_bs_changed= TRUE;
X			if (_w_bs.button == e->button &&
X					_w_bs.w == e->window) {
X				/* Multiple-click detection; must be done
X				   before setting new values */
X				if (e->time <= _w_bs.time + DCLICKTIME) {
X					int dx= e->x - _w_bs.x;
X					int dy= e->y - _w_bs.y;
X					isdclick= (dx*dx + dy*dy <=
X						DCLICKDIST*DCLICKDIST);
X				}
X			}
X			if (!isdclick)
X				_w_bs.clicks= 0;
X			++_w_bs.clicks;
X			_w_bs.mask= e->state / Button1Mask; /* XXX */
X			_w_bs.button= e->button;
X			_w_bs.time= e->time;
X			_w_bs.win= win;
X			_w_bs.w= w;
X			for (_w_bs.isub= NSUBS; --_w_bs.isub >= 0; ) {
X				if (w == win->subw[_w_bs.isub].wid)
X					break;
X			}
X			if (_w_bs.isub < 0) {
X				_wdebug(0, "ll_button: can't find subwin");
X				_w_bs.isub= 0;
X				return;
X			}
X			_w_bs.x= _w_bs.xdown= e->x;
X			_w_bs.y= _w_bs.ydown= e->y;
X		}
X	}
X	else { /* Continue existing sequence */
X		if (win == _w_bs.win && w != _w_bs.w) {
X			/* Maybe changed between mbar and mwin? */
X			if (_w_bs.isub == MBAR && w == win->mwin.wid) {
X				/* Change it -- because of XGrabPointer */
X				_wdebug(3, "MBAR grabbed button");
X				_w_bs.isub = MWIN;
X				_w_bs.w = w;
X			}
X		}
X		if (win != _w_bs.win || w != _w_bs.w) {
X			/* XXX This still happens -- why? */
X			_wdebug(0, "ll_button: inconsistent _w_bs");
X			_w_bs.down= FALSE;
X			_w_bs.mask= 0;
X			_w_bs_changed= TRUE;
X		}
X		else {
X			_w_bs.mask= e->state / Button1Mask; /* XXX */
X			_w_bs.x= e->x;
X			_w_bs.y= e->y;
X			_w_bs.time= e->time;
X			if (e->type == ButtonRelease &&
X				e->button == _w_bs.button) {
X				_w_bs.down= FALSE;
X				_w_bs_changed= TRUE;
X			}
X			else
X				_w_moved= TRUE;
X		}
X	}
X	_wdebug(5, "ll_button: xy=(%d, %d), down=%d, clicks=%d",
X		_w_bs.x, _w_bs.y, _w_bs.down, _w_bs.clicks);
X}
X
Xstatic
Xll_expose(e, win)
X	XExposeEvent *e;
X	WINDOW *win;
X{
X	Window w= e->window;
X	
X	_wdebug(3, "ll_expose called, count=%d, x=%d,y=%d,w=%d,h=%d",
X		e->count, e->x, e->y, e->width, e->height);
X	if (w == win->wa.wid)
X		wchange(win, e->x, e->y, e->x + e->width, e->y + e->height);
X	else if (w == win->mbar.wid)
X		win->mbar.dirty= TRUE;
X	else if (w == win->hbar.wid)
X		win->hbar.dirty= TRUE;
X	else if (w == win->vbar.wid)
X		win->vbar.dirty= TRUE;
X	else {
X		_wdebug(3, "ll_expose: uninteresting event");
X		return;
X	}
X	if (e->count == 0)
X		_w_dirty= TRUE;
X}
X
Xstatic
Xll_configure(e, win)
X	XConfigureEvent *e;
X	WINDOW *win;
X{
X	if (e->window != win->wo.wid) {
X		_wdebug(0, "ll_configure: not for wo.wid");
X		return;
X	}
X	win->wo.x= e->x + e->border_width;
X	win->wo.y= e->y + e->border_width;
X	win->wo.border= e->border_width;
X	if (win->wo.width != e->width || win->wo.height != e->height) {
X		/* Size changed */
X		win->wo.width= e->width;
X		win->wo.height= e->height;
X		_wmovesubwins(win);
X		win->resized= _w_resized= TRUE;
X	}
X}
END_OF_FILE
if test 8971 -ne `wc -c <'Ports/x11/llevent.c'`; then
    echo shar: \"'Ports/x11/llevent.c'\" unpacked with wrong size!
fi
# end of 'Ports/x11/llevent.c'
fi
echo shar: End of archive 7 \(of 19\).
cp /dev/null ark7isdone
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