[comp.windows.news] cyber.shar.splitab

don@TUMTUM.CS.UMD.EDU (Don Hopkins) (11/24/89)

And here's a repost of splitab, which didn't seem to make it through.

	-Don

======== START OF cyber.shar.splitab ========
X	% else's frame menu, and if you mess with the frame menu you're
X	% asking for trouble anyway.)
X        { /clone&forward { % /msg => -
X	    /flipstyle self send
X	    ThisWindow dup null eq {
X		pop /win where {pop win} { % Foo on spin...
X		  /window where {pop window} { % Foo on othello...
X		    /dont-mess-with-the-frame-menu dbgbreak
X		  } ifelse
X		} ifelse
X	    } if
X	    /FrameMenu
X	    2 index put
X	    send
X	  } def
X	  /insertitem { /insertitem clone&forward } def
X	  /deleteitem { /deleteitem clone&forward } def
X	  /changeitem { /changeitem clone&forward } def
X	} ClassFrameMenu send
X
Xclassend def
X
Xsystemdict /DontSetDefaultWindow known not {
X  /DefaultWindow QuickWindow def
X
X  % Hack to make ScrollWindow a subclass of QuickWindow. (gross)
X  /ScrollWindow load type /arraytype eq {
X    10 dict begin
X      /LiteWindow DefaultWindow def
X      ScrollWindow pop
X    end
X  } if
X} if
X
Xend % systemdict
//go.sysin dd *
if [ `wc -c < quickwin.ps` != 7663 ]; then
	made=false
	echo error transmitting quickwin.ps --
	echo length should be 7663, not `wc -c < quickwin.ps`
else
	made=true
fi
if $made; then
	chmod 644 quickwin.ps
	echo -n '	'; ls -ld quickwin.ps
fi
echo Extracting textcan.ps
sed 's/^X//' <<'//go.sysin dd *' >textcan.ps
X%
X% This file is a product of Sun Microsystems, Inc. and is provided for
X% unrestricted use provided that this legend is included on all tape
X% media and as a part of the software program in whole or part.  Users
X% may copy or modify this file without charge, but are not authorized to
X% license or distribute it to anyone else except as part of a product
X% or program developed by the user.
X%
X% THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
X% WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
X% PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
X%
X% This file is provided with no support and without any obligation on the
X% part of Sun Microsystems, Inc. to assist in its use, correction,
X% modification or enhancement.
X%
X% SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
X% INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE
X% OR ANY PART THEREOF.
X%
X% In no event will Sun Microsystems, Inc. be liable for any lost revenue
X% or profits or other special, indirect and consequential damages, even
X% if Sun has been advised of the possibility of such damages.
X%
X% Sun Microsystems, Inc.
X% 2550 Garcia Avenue
X% Mountain View, California  94043
X%
X%
X%	textcan.ps 1.10 89/03/07
X%
X%------------------------------   TextCanvas   --------------------------------
X%
X%	Copyright (c) 1987 by Sun Microsystems, Inc.
X%	Steve Isaac 12/18/87
X%
X% TextCanvas User's Guide
X% -----------------------
X% Description:
X%    TextCanvas is a NeWS class that provides a generic text storage and
X%    display facility NeWS server. It has the following features:
X%	. Scrolling
X%	. Text caret
X%	. Selections (integrated with system selections)
X%    	. Text may be larger than the display canvas
X%	. Display canvas can be positioned anywhere over the stored text
X%	. Font and point size may be changed dynamically
X%	. Colors may be changed dynamically
X%	. No limitations on width of text
X%	. Fixed number of lines of text, specified at creation time
X%	. Currently limited to fixed-width fonts
X%
X%    The TextCanvas allows text-based applications (terminal emulators,
X%    text editors, text widgets) to be easily written. It is a start at
X%    a common platform for NeWS text-oriented applications.
X%
X%    The following things need to be done to TextCanvas in order to fully
X%    achieve this goal:
X%
X%       . Support for variable width fonts and simultaneous multiple fonts
X%         (maybe a subclass if this causes too big a performance hit)
X%       . Text attributes (ie. reversed, blinking, bold, etc).
X%       . Separation of Text array and TextCanvas (to allow multiple
X%            views onto the same text)
X%       . Completion of selection service (multiple clicks, etc)
X%       . Dynamic changing of the number of lines of text
X%       . The caret should be a seperate class
X%       . The terminal emulation specifics (coordinate system, scrolling)
X%            should be a seperate subclass
X%       . Continuing performance improvements
X%
X% Overview:
X%    The TextCanvas can be viewed as a NeWS canvas that understands a set
X%    of messages relating to text manipulation (eg. inserting a string,
X%    deleting some lines, moving the caret). Basic canvas operations
X%    (eg. shaping, resizing, moving) are done via standard NeWS primitives.
X%    All canvas operations can be freely performed, however, the TextCanvas
X%    must be informed if the canvas is resized, damaged, or destroyed.
X%
X%    A TextCanvas has an underlying fixed-size text array that contains
X%    arbitrarily long strings. The canvas is essentially a viewport into this
X%    array; this viewport may be moved around to display different parts of
X%    the text aray. It cannot be moved outside the boundries of the
X%    text array, however.
X%
X%    An instance of TextCanvas is created by specifying an existing canvas
X%    and the number of lines that the Text array will store. This canvas
X%    could be the client canvas of a window, which is how the TextCanvas
X%    typically interfaces to the LiteWindow package.
X%
X% Coordinates:
X%    The TextCanvas presents an integer coordinate system that addresses each
X%    possible chararcter position in the Text array. It is laid out as follows:
X%
X%         1,-N ------------------ W,-N  <------+
X%          |                       |           |
X%          |                       |           |
X%          |                       |           |
X%          |                       |           |
X%          |                       |           |
X%         1,-1                    W,-1         +-- NumLines
X%         1,0                     W,0          |
X%         1,1 ------------------- W,1          |
X%         1,2                     W,2          |
X%          |                       |           |
X%          |                       |           |
X%          |                       |           |
X%         1,H ------------------- W,H   <------+
X%
X%    where: W is the largest width of any string in the text array,
X%           H is the number of lines that fit in the viewport canvas,
X%           NumLines is the number of lines in the text array,
X%           N is: NumLines - H - 1.
X%
X%    This means that the lines of the Text array under the original viewport
X%    postion are addressed starting at 1, with increasing line numbers going
X%    down the viewport.
X%
X%    Note that W is always changing as new lines of text are written
X%    into the Text canvas. The coordinate system will change if the
X%    viewport canvas is resized.
X%
X% Scrolling:
X%    Text which is written at line number H+1 or greater will cause
X%    the entire Text array to scroll up so that the last line written
X%    is at line H. Lines 0 through -N are therefore a transcript of
X%    what was displayed in the viewport. Upwards scrolling can also be caused
X%    by cursor movement (movecursordelta).
X%
X%    Downwards scrolling is limited to the original viewport area only. It is
X%    caused by cursor movement (movecursordelta).
X%
X%    Scrolling can be limited to a portion of the text array (via
X%    setscrollinglimits).
X%
X% Moving the viewport:
X%    The viewport can be moved to display non-visible portions of the text
X%    arrray. Note that the coordinate system does not change if the viewport
X%    is moved. It remains relative to the original viewport position. Movement
X%    is requested via the moveviewport message.
X%
X% Caret:
X%    The TextCanvas contains a built-in text caret that can be turned
X%    on or off, be any color, be any shape that can be expressed as a
X%    PostScript path, made to blink at a user-defined speed and duty
X%    cycle, and moved to any coordinate location. The caret is positioned
X%    just to the left and below the location it is on.
X%
X% Writing text:
X%    Text is put into the text array via the writelines, and writeatcaret
X%    messages. They allow large blocks of text to be written in a single
X%    message. There is a big performance win for writing as large
X%    a block as possible. Text must consist of printable chararacters (ASCII
X%    codes 0x20-0x7E) only. Non-printable characters will cause erroneous
X%    selections. There is no special interpretation for control characters.
X%
X% Selections:
X%    The TextCanvas provides a MacIntosh-like selection mechanism.
X%    Left mouse button down sets the selection start point. Dragging the
X%    mouse with the left button down drags out a selection. Left mouse
X%    button up completes the selection. The middle mouse button allows
X%    the current selection to be extended, either by clicking or by dragging.
X%
X%    The selected text is made the PrimarySelection in the system selection
X%    dictionary. Any previous primary selection is cleared. The selected text
X%    can be accessed via the standard system selection call (getselection).
X%    If LiteUI is running then the "Put" function key will put the selection
X%    on the shelf.
X%
X% Input Handling and Callback Routines:
X%    The TextCanvas expresses interest in keyboard events. An optional
X%    user-supplied callback routine (KeyHitCallback) is called whenever a
X%    keystroke is detected. Similarly, another callback routine
X%    (InsertValueCallback) is called when a selection /InsertValue
X%    event is detected.
X%
X%    A callback routine for when the number of rows and columns in the
X%    viewport changes (ResizeCallback) is provided. Callbacks for mouse button
X%    events (LeftMouseDownCallback, LeftMouseUpCallback,
X%    MiddleMouseDownCallback, MiddleMouseUpCallback) are also provided. Other
X%    callbacks may be added by subclassing the text canvas.
X%
X%    These callback routines make it very easy to write short routines
X%    do things like echo what the user has typed or move the caret to where
X%    the mouse was clicked.
X%
X%    The callback routine will be executed within the context of the the
X%    TextCanvas instance. You may access all TextCanvas instance or class
X%    variables, or invoke methods by simply calling them as procedures.
X%
X% TextCanvas Interface Definition
X% -------------------------------
X%    The messages and callback routines that class TextCanvas provides are:
X%
X%  /changefont	{ % fname fheight - => -
X%  --- Change the font and point size for all text. Either fname or fheight
X%      may be null, in which case they are ignored.
X%
X%  /writelines {  % arrayofstrings col row => -
X%  --- Write an array of strings, starting the first string at col,row
X%      with subsequent strings going at 1,row+1 1,row+2 etc.
X%
X%  /writeatcaret {  % arrayofstrings => -
X%    --- Similar to writelines, except start at the current caret location. The
X%        caret is moved to the next available character position when the
X%        write is done.
X%
X%  /deletestring { % length col row => -
X%    --- Delete a string starting at col,row for length characters.
X%        length must be 0 or a positive integer.
X%
X%  /insertline { % numlines row => -
X%    --- Insert numlines blank lines, starting at line row.
X%        numlines must be 0 or a positive integer
X%
X%  /deleteline { % numlines row => -
X%    --- Delete numlines lines, starting at line row.
X%        numlines must be 0 or a positive integer
X%
X%  /setscrollinglimits { % toprow bottomrow => -
X%    --- Sets the scrolling limits for the TextCanvas. All up or down scrolling
X%        will be limited to this region instead of affecting the entire Text
X%        canvas. When scrolling limits are set, those methods which can
X%        trigger scrolling (writelines, writeatcaret, movecaretdelta) will
X%        only cause scrolling if they affect lines within the scrolling region.
X%        Any scrolling that is initiated will only move lines within the
X%        scrolling limits.
X%
X%  /removescrollinglimits { % - => -
X%    --- Removes any scrolling bounds set by setscrollinglimits.
X%
X%  /clearviewport { % - => -
X%    --- Clear the text and screen area of the viewport
X%
X%  /flashviewport { % - => -
X%    --- Flash the contents of the viewport (visible bell)
X%
X%  /moveviewport { % x y => -
X%    --- Move the viewport to another part of the underlying Text array.
X%        x and y must be between 0 and 1. This represents a percentage of the
X%        current total width or height of the Text array. Either argument
X%        can be null, in which case it is ignored.
X%
X%  /getviewportsize { % - => col rows xpixels ypixels
X%    --- Return the number of columns, rows, pixel height and width of
X%        the viewport.
X%
X%  /getlinelength { % row => length
X%    --- Return the current length of the line at row.
X%
X%  /calcarea { % pixwidth pixheight => numcols numrows
X%    --- Returns the number of rows and columns that will fit into the pixel
X%        area specified by pixwidth and pixheight, given the current Font and
X%        point size.
X%
X%  /calcpixarea { % numcols numrows => pixwidth pixheight
X%    --- Returns the minimum pixel area required to display numrows and numcols,
X%        given the current Font and point size.
X%
X%  /oncaret {   %   - => -
X%    --- Turn the caret on.
X%
X%  /offcaret {   %   - => -
X%    --- Turn the caret off.
X%
X%  /movecaret { % col row => -
X%    --- Move the caret to an absolute position. col and row are integers. Scrolling is
X%        never triggered.
X%
X%  /movecaretdelta { % deltax deltay => -
X%    --- Move the caret relative to its current position. deltax and deltay must be
X%        integers (negatives allowed). Scrolling is triggered if deltay moves the caret
X%        outside of the scrolling limits. If no scrolling limits are set, scrolling is
X%        triggered if deltay moves the caret outside of the original viewport region.
X%
X%  /setcaretblink {   %   blink-rate duty-cycle => -
X%    --- Set the caret blink rate and the blink duty cycle. blink-rate is
X%        in seconds and represents a complete on/off cycle. duty-cycle is
X%        between 0 and 1, and represents the percentage of on time.
X%
X%  /setcaretcolor {   %   color => -
X%    --- Set the current caret color. color is a color object.
X%
X%  /setcaretshape {  % shapename => successful?
X%    --- Set the caret shape. shapename is an entry in the CaretShapeDict.
X%        Return a boolean that tells whether shapename was found.
X%
X%  /getcaretpos {   % - => col row
X%    --- Return the current caret position
X%
X%  /setbgcolor { % color => -
X%    --- Set the current canvas background color
X%
X%  /setfgcolor { % color => -
X%    --- Set the current text color
X%
X%  /fixdamage { % - => -
X%    --- Damage handler; goes in the PaintClient window callback routine
X%
X%  /new { % numrows can => object
X%    --- Create a new instance of the TextCanvas. numrows is the number
X%        of lines to be allocated in the Text array; it is fixed for
X%        the life of the instance. can is the viewport canvas.
X%
X%  /reshape { % - => -
X%    --- This method must be called whenever the viewport canvas has changed
X%        size. It updates the number of rows and columns in the TextCanvas,
X%        repositions the caret to be as close to its old position as possible,
X%        resets the scrolling region, and moves the viewport to its original
X%        position.
X%
X%  /destroy { % - => -
X%    --- Destroy the TextCanvas. This must be called if the viewport canvas
X%        is ever destroyed.
X%
X% --- Client callback routines.
X%  /ResizeCallback	nullproc	def % { - => -
X%    --- ResizeCallback is called whenever the number of rows and columns
X%        changes.
X%  /KeyHitCallback	nullproc	def % { keyvalue - => -
X%    --- KeyHitCallback is called whenever a keyboard input event happens
X%  /InsertValueCallback	nullproc	def % { insertstring => -
X%    --- InsertValueCallback is called whenever an InsertValue event happens
X%  /LeftMouseDownCallback nullproc	def % { col row => -
X%    --- LeftMouseDownCallback is called when the left mouse button goes down.
X%  /LeftMouseUpCallback nullproc	def % { col row => -
X%    --- LeftMouseUpCallback is called when the left mouse button goes up.
X%  /MiddleMouseDownCallback nullproc	def % { col row => -
X%    --- MiddleMouseDownCallback is called when the middle button goes down.
X%  /MiddleMouseUpCallback nullproc	def % { col row => -
X%    --- MiddleMouseUpCallback is called when the middle button goes up.
X%
X% Implementation Details
X% ----------------------
X% Coordinates:
X%    The text canvas has an internal coordinate system as follows:
X%
X%    1,1 --------- TextWidth,1
X%     |                |
X%     |                |
X%    1,TextHeight  TextWidth,TextHeight
X%
X%    The Can canvas is essentially a viewport on this coordinate system. The
X%    TM tranformation matrix reflects this coordinate system, and is used for
X%    computing caret or text movement on Can. The base window lives in the
X%    lower left hand corner of the text canvas, the original location of the
X%    viewport. It is the same size as the Can canvas. External caret
X%    coordinates are relative to the base window; the internal caret
X%    coordinates (CaretX, CaretY) are relative to the internal coordinate
X%    system. The text array is laid out in a similar fashion to the internal
X%    coordinate system; however, indices are 0 based. The Xindex and Yindex
X%    functions map coordinate values to array indices. Text scrolling is
X%    handled by manipulating this mapping.
X%
X
X%systemdict /TextCanvas known not {
Xsystemdict begin
X/TextCanvas Object
Xdictbegin
X   /DEBUG		false		def % Turn on debugging output
X   /Text		null		def % Main text array
X   /TextWidth		0		def % Number of text columns (changes
X					    % dynamically)
X   /TextHeight		0		def % Number of text rows (specified
X					    % at initialization)
X   /Can			null		def % The main canvas
X   /SelectionCan	null		def % Visible selection feedback canvas
X   /SelDragCan		null		def % Transparent selection drag canvas
X   /Caret     		null    	def % The caret canvas
X
X   /CanPixWidth		0		def % Canvas width (pixels)
X   /CanPixHeight	0		def % Canvas height (pixels)
X   /CanPixX		0		def % Canvas X origin (pixels)
X   /CanPixY		0		def % Canvas Y origin (pixels)
X   /CanX    		0		def % Canvas X origin (Text coordinates)
X   /CanY		0		def % Canvas Y origin (Text coordinates)
X   /CanWidth		0		def % Number of columns in canvas
X   /CanHeight		0		def % Number of rows in canvas
X
X   % --- Caret variables.
X   /CaretOn?		false		def % Is the caret on?
X   /CaretInactive?	false		def % Is the caret inactive (shaded,
X					    % no blink)?
X   /CaretSupressed?  	false		def % Is the caret supressed
X					    % (temporarily off)?
X   /NextMoveTime    	0		def % Time at which to do the next
X					    % caret move
X   /DelayedMoveProc   	null		def % Delayed caret move timer process
X   /CaretX		1		def % Caret column in canvas
X   /CaretY		1		def % Caret row in canvas
X   /CaretShape  	/TrianglePlus 	def % Current caret shape (from
X					    % CaretShapeDict)
X   /CaretColor		null 		def % Current caret color
X   /CaretBlinkEnabled?	true		def % Are we blinking?
X   /CaretBlinkTime	1.0		def % Seconds
X   /CaretDutyCycle	0.8		def % Percentage on
X   /CaretDelayTime	.06 		def % Caret move delay time (seconds)
X
X   /EventMgr		null		def % The main event manager
X   /Interests		null		def % Main event manager interests
X   /MouseDragEventMgr	null 		def % Event manager for mouse dragging
X   /DragInterests	null		def % Drag event manager interests
X   /KeyboardEventMgr	null		def % Keyboard/Insert_Value event mgr
X
X   % --- Selection variables.
X   /MouseDownX		0		def % Where MouseDown actually happened
X   /MouseDownY		0		def
X   /SelectionX		1		def % Current initial selection point
X   /SelectionY		1		def
X   /SelectionX1		1		def % Current ending selection point
X   /SelectionY1		1		def
X   /SelExtendTop?	false		def % Extend the top of the selection
X   /SelectionOn?	false		def % Is the selection visible?
X   /SelectionPath	null		def % Current path of the visible
X					    % selection
X
X   /SelectionDict 10 dict dup begin	    % Dictionary for i/f to system
X					    % selections
X      /ContentsAscii null		def
X      /SelectionObjSize 1		def
X      /SelectionResponder null		def
X    end def
X
X   /ViewportXdelta	0		def % Viewport offset adjustment
X   /ViewportYdelta	0		def % Viewport offset adjustment
X   /WriteInProgress?    false		def % Is there text output happening?
X   /BotScrollLimit  	0		def % Scrolling limit for bottom of screen
X   /TopScrollLimit  	0		def % Scrolling limit for top of screen
X   /ScrollRegionLength 	0		def % Number of lines in scrolling region
X   /ScrollLimitOn?	false		def % Are scrolling limits in effect?
X   /BaseY  		0		def % Base window Y position in Text
X   /PixColWidth  	0		def % Row width (pixels)
X   /PixRowHeight	0		def % Column height (pixels)
X   /TM			null		def % Position tranform matrix
X   /Font		null		def % Current font
X   /FontDescentTM	null		def % TM plus font descent
X   /MapOffset		0		def % Y array index offset
X   /InputBuffer		null		def % Input line buffer.
X   /InputBufferLine	0		def % Line that input buffer is on
X   /InputBufferLength	0		def % Number of characters in the buffer
X   /BgColor		1 1 1 rgbcolor	def % Current background color
X   /FgColor		0 0 0 rgbcolor	def % Current foreground color
X   /KeyboardInterest	null		def % Need to keep this so we can revoke
X					    % it at destroy time to free memory
X   /MoreInterests	null		def % But wait, there's more!
X   % --- Client callback routines.
X   % --- ResizeCallback is called whenever the number of rows and columns
X   %     changes.
X   /ResizeCallback	nullproc	def % { - => -
X   % --- KeyHitCallback is called whenever a keyboard input event happens
X   /KeyHitCallback	nullproc	def % { keyvalue - => -
X   % --- InsertValueCallback is called whenever an InsertValue event happens
X   /InsertValueCallback	nullproc	def % { insertstring => -
X   % --- LeftMouseDownCallback is called when the left mouse button goes down.
X   /LeftMouseDownCallback nullproc	def % { col row => -
X   % --- LeftMouseUpCallback is called when the left mouse button goes up.
X   /LeftMouseUpCallback nullproc	def % { col row => -
X   % --- MiddleMouseDownCallback is called when the middle button goes down.
X   /MiddleMouseDownCallback nullproc	def % { col row => -
X   % --- MiddleMouseUpCallback is called when the middle button goes up.
X   /MiddleMouseUpCallback nullproc	def % { col row => -
Xdictend
Xclassbegin
X   /LF 			10   		def
X   /CR 			13   		def
X   /BLANK		32   		def
X
X   /FontName		/Screen  	def
X   /FontHeight		14       	def
X
X   /DefaultColorCaret  1 0 0 rgbcolor 	def
X   /DefaultMonoCaret   0 0 0 rgbcolor	def
X   /DefaultInactiveColor ColorDisplay?
X	                    {.75 .75 .75 rgbcolor}
X			    {.5 .5 .5 rgbcolor}
X                         ifelse         def
X
X%-------------------------------- Utilities ------------------------------------
X
X   /?def {
X      currentdict 2 index known {
X         pop pop
X      }{
X         def
X      } ifelse
X   } def
X
X   /LoadCaretShapeDict {
X   systemdict /CaretShapeDict known not {
X      systemdict begin /CaretShapeDict dictbegin dictend def end
X   } if
X   CaretShapeDict begin % --- Caret Shape dictionary
X      /HLine {  % xscale yscale => {path}
X	 matrix currentmatrix 3 1 roll
X            dup scale
X            pop
X	    0 0 moveto
X            0 .8 transform round exch round exch itransform rlineto
X            -0.3 0 transform round exch round exch itransform rlineto
X	    0 -1 transform round exch round exch itransform rlineto
X         setmatrix
X      } ?def
X
X      /Diamond {  % xscale yscale => {path}
X	 matrix currentmatrix 3 1 roll
X            dup scale
X            pop
X	    0 0 moveto 0.25 0 rmoveto 0.25 0.25 rlineto
X	    -0.25 0.25 rlineto -0.25 -0.25 rlineto closepath
X	 setmatrix
X      } ?def
X
X      /TrianglePlus {  % xscale yscale => {path}
X         matrix currentmatrix 3 1 roll
X            dup scale
X            pop
X            0 0 moveto
X            0 .8 transform round exch round exch itransform rlineto
X            -0.1 0 transform round exch round exch itransform rlineto
X	    0 -.8 transform round exch round exch itransform rlineto
X            -0.35 -0.4 transform round exch round exch itransform rlineto
X            .35 0 transform round exch round exch itransform rlineto
X            .1 0 transform round exch round exch itransform rlineto
X            .35 0 transform round exch round exch itransform rlineto
X	    closepath
X         setmatrix
X      } ?def
X
X      /Triangle {  % xscale yscale => {path}
X         matrix currentmatrix 3 1 roll
X            dup scale
X            pop
X	    0 0 moveto
X            -0.3 -0.6 transform round exch round exch itransform rlineto
X            .6 0 transform round exch round exch itransform rlineto
X            -0.3 0.6 transform round exch round exch itransform rlineto
X         setmatrix
X      } ?def
X
X      /Box {  % xscale yscale => {path}
X         matrix currentmatrix 3 1 roll
X           scale
X 	   0 0 moveto
X           0 1 rlineto
X           1 0 rlineto
X           0 -1 rlineto
X           -1 0 rlineto
X           -.1 -.1 rmoveto
X           0 1.2 rlineto
X           1.2 0 rlineto
X           0 -1.2 rlineto
X           closepath
X         setmatrix
X      } ?def
X   end
X   } def
X
X   /Xindex { % col => x-index
X   % --- Convert a column coordinate into a Text array index
X      1 sub
X   } def
X
X   /Yindex { % row => y-index
X   % --- Convert a row coordinate into a Text array index
X   % Text array
X      1 sub MapOffset add TextHeight mod
X   } def
X
X   /CreateInterests { % - => -
X      % --- Main event handler interests
X      /Interests dictbegin
X
X         /CaretDamageEvent
X            /Damaged
X            {pop gsave
X   	       Caret setcanvas
X               CaretInactive? {
X   	          DefaultInactiveColor fillcanvas
X               }{
X   	          CaretColor fillcanvas
X               } ifelse
X   	     grestore }
X            null Caret eventmgrinterest
X         def
X
X         /CaretTimerEvent
X         % --- Caret blink events. Send this event out again with the time
X         %     of the next blink
X            /CaretTimer
X            {/e exch def
X             e begin
X   	     Caret /Mapped get {
X                CaretBlinkEnabled? CaretOn? CaretInactive? not CaretSupressed? not
X                and and and {
X   	           UnMapCaret
X   		   /TimeStamp
X   		      % --- When to turn caret back on
X   		      CaretBlinkTime 60 div 1 CaretDutyCycle
X		      sub mul currenttime add
X   		   def
X                }{
X                   % --- If the caret is disabled, keep the timer event
X		   %     circulating at a 2 second rate
X                   /TimeStamp currenttime 1 30 div add def
X                } ifelse
X   	     }{
X                CaretBlinkEnabled? CaretOn? CaretInactive? not CaretSupressed? not
X                and and and {
X   		   MapCaret
X   		   /TimeStamp
X   		      % --- When to turn caret back off
X   		      CaretBlinkTime 60 div CaretDutyCycle mul
X   		      currenttime add
X   		   def
X                }{
X                   % --- If the caret is disabled, keep the timer event
X		   %     circulating at a 2 second rate
X                   /TimeStamp currenttime 1 30 div add def
X                } ifelse
X   	     } ifelse
X             e sendevent
X   	    end}
X            null Caret eventmgrinterest
X         def
X
X         /LeftMouseDownEvent
X            /LeftMouseButton
X	    {begin
X               InactivateCaret
X               % --- Clear anyone else's primary selection
X               SendClearSelection
X               % --- Synchronously clear my primary selection
X               ClearMySelection
X               Can setcanvas
X	       TM setmatrix
X               /MouseDownX XLocation 1 max round store
X               /SelectionX MouseDownX store
X               /SelectionX1 SelectionX store
X               /MouseDownY YLocation TextHeight min CanY max round store
X               /SelectionY MouseDownY store
X               /SelectionY1 SelectionY store
X               /len Text SelectionY Yindex get length store
X               SelectionX len 2 add gt {
X                  /SelectionX len 2 add store
X               } if
X               /SelExtendTop? false def
X               /MouseDragEventMgr
X                  DragInterests forkeventmgr
X               store
X               MouseDownX MouseDownY BaseY sub LeftMouseDownCallback
X             end }
X            /DownTransition Can eventmgrinterest
X         def
X
X         /MiddleMouseDownEvent
X            /MiddleMouseButton
X	    {begin
X               InactivateCaret
X               % --- Clear anyone else's primary selection
X               SendClearSelection
X               % --- Remove any visual feedback for my selection, but leave
X               %     the selection path intact so we can extend it.
X               false DrawSelection
X               SelDragCan setcanvas
X               TM setmatrix
X               YLocation SelectionY sub abs dup mul
X                 XLocation SelectionX sub abs dup mul add
X                 YLocation SelectionY1 sub abs dup mul
X                 XLocation SelectionX1 sub abs dup mul add lt {
X                  /SelectionX XLocation 1 max round store
X                  /SelectionY YLocation TextHeight min CanY max round store
X                  /SelExtendTop? true store
X               }{
X                  /SelectionX1 XLocation 1 max round store
X                  /SelectionY1 YLocation TextHeight min CanY max round store
X                  /SelExtendTop? false store
X               } ifelse
X               ExtendSelection
X               /MouseDragEventMgr
X                  DragInterests forkeventmgr
X               store
X               XLocation 1 max round YLocation TextHeight min CanY max round BaseY sub
X                  MiddleMouseDownCallback
X             end}
X            /DownTransition Can eventmgrinterest
X         def
X
X       dictend store  % Interests
X   } def
X
X   /CreateDragInterests { % - => -
X   % --- Interests for mouse drag event manager
X      /DragInterests dictbegin
X          /MouseDragEvent
X             /MouseDragged
X             { begin
X                  SelDragCan setcanvas
X		  TM setmatrix
X                  SelExtendTop? {
X                     /SelectionX XLocation 1 max round store
X                     /SelectionY YLocation TextHeight min CanY max round store
X                  }{
X                     /SelectionX1 XLocation 1 max round store
X                     /SelectionY1 YLocation TextHeight min CanY max round store
X                  } ifelse
X                  erasepage
X                  ExtendSelection
X               end}
X 	     null Can eventmgrinterest
X          def
X
X          /LeftMouseUpEvent
X             /LeftMouseButton
X	     {begin
X                SelDragCan setcanvas
X	        erasepage
X                Can setcanvas
X                TM setmatrix
X                % --- If we are at the same location as LeftButton down, then
X                % remove any selection on our canvas. Otherwise, make the selected
X                % area the primary selection.
X                MouseDownX XLocation 1 max round eq
X                MouseDownY YLocation TextHeight min CanY max round eq and {
X                   false DrawSelection
X                   /SelectionPath null store
X                }{
X                   % --- SelectionX,Y must always be lower than SelectionX1,Y1
X                   SelectionY1 SelectionY lt SelectionY1 SelectionY eq
X	             SelectionX1 SelectionX lt and or {
X                      SelectionX SelectionY
X                      /SelectionX SelectionX1 store
X                      /SelectionY SelectionY1 store
X                      /SelectionY1 exch store
X                      /SelectionX1 exch store
X                   } if
X                   SelectionDict /ContentsAscii GetSelection put
X                   SelectionDict /Canvas Can put
X                   SelectionDict /SelectionHolder KeyboardEventMgr put
X                   SelectionDict /PrimarySelection setselection
X                   true DrawSelection
X                } ifelse
X                ReactivateCaret
X                XLocation 1 max round YLocation TextHeight min CanY max round BaseY sub
XLeftMouseUpCallback
X                MouseDragEventMgr killprocess
X              end}
X             /UpTransition null eventmgrinterest
X          def
X
X          /MiddleMouseUpEvent
X             /MiddleMouseButton
X	     {begin
X                SelDragCan setcanvas
X	        TM setmatrix
X	        erasepage
X                % --- SelectionX,Y must always be lower than SelectionX1,Y1
X                SelectionY1 SelectionY lt SelectionY1 SelectionY eq
X	          SelectionX1 SelectionX lt and or {
X                   SelectionX SelectionY
X                   /SelectionX SelectionX1 store
X                   /SelectionY SelectionY1 store
X                   /SelectionY1 exch store
X                   /SelectionX1 exch store
X                } if
X                SelectionDict /ContentsAscii GetSelection put
X                SelectionDict /Canvas Can put
X                SelectionDict /SelectionHolder KeyboardEventMgr put
X                SelectionDict /PrimarySelection setselection
X                true DrawSelection
X                ReactivateCaret
X                XLocation round YLocation TextHeight min CanY max round BaseY sub MiddleMouseUpCallback
X                MouseDragEventMgr killprocess
X             end}
X             /UpTransition null eventmgrinterest
X          def
X      dictend store
X   } def
X
X   /KeyboardHandler { % - => -
X      % --- Handler for keyboard, InsertValue, and Deselect events
X      /KeyboardInterest Can addkbdinterests def
X      /MoreInterests [
X        Can addselectioninterests aload pop
X	revokeinterest % Get rid of mouse interests
X        Can addfunctionstringsinterest
X      ] def
X      { awaitevent begin
X           Name type /integertype eq {
X              Name /KeyHitCallback self send
X           } if
X           Name /DeSelect eq {
X              false DrawSelection
X              /SelectionPath null store
X           } if
X	   Name /LoseFocus eq {
X	      InactivateCaret
X	   } if
X           Name /RestoreFocus eq {
X              ReactivateCaret
X           } if
X           Name /InsertValue eq {
X              Action /InsertValueCallback self send
X           } if
X           Name /Ignore eq {
X           } if
X        end
X      } loop
X   } def
X
X   /InitFont { % - => -
X   % --- Initialize the current font and font metrics
X   10 dict begin
X      /Font FontName findfont FontHeight scalefont store
X      gsave
X         false setprintermatch
X         Font setfont (m) stringwidth pop /PixColWidth exch store
X      grestore
X      /PixRowHeight Font fontheight store
X   end
X   } def
X
X   /Reshape { % firsttime? => -
X   % --- Reshape the TextCanvas. This is where all initialization happens.
X   %     firsttime is true the first time the TextCanvas is reshaped;
X   %     false otherwise.
X   %
X      % --- Note: we are not enclosing this proc in a '10 dict begin end'
X      %     because the event handlers must be started with the class dict
X      %     being first on the dictionary stack. This results in firsttime?
X      %     being put into the instance dictionary.
X      /firsttime? exch def
X      % --- Take down the caret and clear any selection that is up
X      firsttime? {
X         LoadCaretShapeDict
X         InactivateCaret
X         /InputBuffer 1024 string def	% Set input line buffer string to a
X					% reasonable size. The buffer will
X					% be grown dynamically if needed
X      }{
X         SupressCaret
X      } ifelse
X      ClearMySelection
X      gsave
X         Can setcanvas
X%         Can /Parent get setcanvas
X%         6 array identmatrix setmatrix % X11/NeWS
X         6 array defaultmatrix setmatrix
X         % --- Set up transformation matrix with font descent at the baseline
X         0 TextHeight PixRowHeight mul
X	    Font fontascent add Font fontdescent sub
X	    translate
X         PixColWidth PixRowHeight neg scale
X	 /FontDescentTM 6 array currentmatrix store
X         % --- Set up transformation matrix for direct mapping of Text coords
X%         6 array identmatrix setmatrix % X11/NeWS
X         6 array defaultmatrix setmatrix
X         0 TextHeight PixRowHeight mul
X	    Font fontascent add
X	    translate
X         PixColWidth PixRowHeight neg scale
X	 /TM 6 array currentmatrix store
X      grestore
X      % --- Initialize the viewport and caret positions. Set the caret to
X      %     1,1 the first time around, try to maintain previous caret
X      %     position subsequently
X      firsttime? {
X         % --- Determine the number of rows and columns in this canvas
X         /CanWidth CanPixWidth PixColWidth idiv 1 sub store
X         /CanHeight CanPixHeight PixRowHeight idiv 1 sub store
X         % --- Initialize the position of the canvas viewport and the caret
X         /CanX 1 store
X         /CanY TextHeight CanHeight sub 1 add store
X         /BaseY CanY 1 sub store
X         /CaretX CanX store
X         /CaretY CanY store
X      }{
X         /CaretX CaretX ViewportXdelta add store
X         /CaretY CaretY ViewportYdelta add store
X         /ViewportXdelta 0 store
X         /ViewportYdelta 0 store
X         % --- Remove any scrolling offset from caret position
X         /CaretX CanX 1 sub CaretX add store
X         /CaretY CanY TextHeight CanHeight sub 1 add sub CaretY add store
X         % --- Determine the number of rows and columns in this canvas
X         /CanWidth CanPixWidth PixColWidth idiv 1 sub store
X         /CanHeight CanPixHeight PixRowHeight idiv 1 sub store
X         % --- Initialize the position of the canvas viewport and the caret
X         /CanX 1 store
X         /CanY TextHeight CanHeight sub 1 add store
X         /BaseY CanY 1 sub store
X         % --- Check if the caret is out of bounds
X         CaretY CanY lt {
X            /CaretY CanY store
X         } if
X         CaretX CanWidth gt {
X            /CaretX CanWidth store
X         } if
X      } ifelse
X      % --- Reset scrolling limits
X      /BotScrollLimit TextHeight store
X      /TopScrollLimit CanY store
X      /ScrollRegionLength BotScrollLimit TopScrollLimit sub 1 add def
X      /ScrollLimitOn? false store
X      % --- Set up the text arrays
X      firsttime? {
X         /Text TextHeight array store
X         % --- Initialize Text array to empty strings
X         0 1 TextHeight 1 sub {
X            Text exch () put
X         } for
X         % --- Initialize the input buffer to blanks
X         0 1 InputBuffer length 1 sub {
X             InputBuffer exch BLANK put
X         } for
X      } if
X      % --- Create the caret if needed
X      Caret null eq {
X         CreateCaret
X         % --- Kick off first blink event
X	 createevent begin
X	     /Canvas    Caret		def
X	     /Name	/CaretTimer	def
X	     /Action    null		def
X	     /TimeStamp
X	  	 CaretBlinkTime 60 div CaretDutyCycle mul currenttime add
X	     def
X	     currentdict
X	 end
X	 sendevent
X      } if
X      % --- Create interests and event managers if they aren't running.
X      %     Note: this must be done with the class instance variable being
X      %     the first thing on the dictionary stack; otherwise the event
X      %     managers won't share the class' instance variables!
X      EventMgr null eq {
X         CreateInterests
X         CreateDragInterests
X         /EventMgr Interests forkeventmgr def
X         /KeyboardEventMgr {KeyboardHandler} fork def
X      } if
X      %SelectionCan null eq {
X         % --- Create the selection feedback canvas
X         %     XXX - Not using the selection canvas yet; still doing xor
X         %/SelectionCan Can newcanvas store
X         %SelectionCan begin
X         %     /Transparent false def
X         %     /EventsConsumed /NoEvents def
X         %end
X      %} if
X      % --- Shape the viewport canvas
X      gsave
X	 Can setcanvas
X         % --- Clear the canvas
X         BgColor fillcanvas
X         % --- Make the canvas size be an even number of rows and cols
X	 Can /Parent get setcanvas
X%         CanPixX CanPixY
X	 Can getcanvaslocation
X	 translate
X	 0 0
X	 CanWidth PixColWidth mul PixColWidth add
X         CanHeight PixRowHeight mul PixRowHeight add
X	 Font fontdescent 2 mul sub
X         rectpath
X         % --- Set the default matrix for the canvas to the identity matrix
X%         6 array identmatrix setmatrix % X11/NeWS
XCan setcanvas clippath
X         6 array defaultmatrix setmatrix
X         Can reshapecanvas
X         % --- Create the outline selection drag canvas
X         /SelDragCan Can createoverlay store
X      grestore
X      /SelectionOn? false def
X      /SelectionPath null def
X      UnSupressCaret
X      MoveCaret
X   } def
X
X   /ClearScreenArea { % x y width height => -
X   % --- Fill the designated area with the background color
X      gsave
X         Can setcanvas
X         FontDescentTM setmatrix
X         4 -2 roll		% width height x y
X	 1 sub			% width height x y-1
X         4 2 roll 		% x y-1 width height
X         rectpath
X         BgColor setcolor fill
X       grestore
X   } def
X
X   /MoveScreenArea { % numlines x y width height => -
X   % --- Move a given area of the screen numlines
X   %     numlines < 0 - move down
X   %        "     > 0 - move up
X      10 dict begin
X         /height exch def
X         /width exch def
X         /y exch def
X         /x exch def
X         /numlines exch def
X         gsave
X            Can setcanvas
X            FontDescentTM setmatrix
X            x y 1 sub width height rectpath
X            0 numlines neg copyarea
X         grestore
X      end
X    } def
X
X   /FlushInputBuffer { % - => -
X      % --- Flush the InputBuffer to Text array if it is in use
X      InputBufferLine 0 ne {
X         % --- Create a standalone string for this line in the Text array
X         Text InputBufferLine Yindex
X            Text InputBufferLine Yindex get InputBufferLength string copy
X         put
X         % --- Blank fill the previously used part of InputBuffer
X         0 1 InputBufferLength {
X             InputBuffer exch BLANK put
X         } for
X         /InputBufferLine 0 store
X         /InputBufferLength 0 store
X      } if
X   } def
X
X   /ScrollUp { % numlines beginrow endrow => -
X   % --- Scroll up numlines from a given line to another line
X      10 dict begin
X         /endrow exch def
X         /beginrow exch def
X         /numlines exch def
X         FlushInputBuffer
X         ClearMySelection
X         /len endrow beginrow sub 1 add def
X         /numlines numlines len min def
X         /inset beginrow numlines add def
X         % --- Move the text
X         beginrow Yindex endrow Yindex le {
X            % --- We can do a fast move if the scroll region doesn't
X            %     wrap around the end of the physical array
X            Text
X              beginrow Yindex Text inset Yindex endrow inset sub 1 add
X              getinterval putinterval
X         }{
X            % XXX This should be done as two getinterval/putintervals
X            beginrow numlines add 1 endrow {
X               /i exch def
X               Text i numlines sub Yindex Text i Yindex get put
X            } for
X         } ifelse
X         endrow numlines sub 1 add 1 endrow {
X            Text exch Yindex () put
X         } for
X         numlines 1 beginrow numlines add TextWidth len numlines sub MoveScreenArea
X         1 endrow numlines sub 1 add TextWidth numlines ClearScreenArea
X      end
X   } def
X
X   /ScrollDown { % numlines beginrow endrow => -
X   % --- Scroll down numlines from a given line to another line
X      10 dict begin
X         /endrow exch def
X         /beginrow exch def
X         /numlines exch def
X         FlushInputBuffer
X         ClearMySelection
X         /len endrow beginrow sub 1 add def
X         /numlines numlines len min def
X         /inset endrow numlines sub def
X         beginrow Yindex endrow Yindex le {
X            % --- We can do a fast move if the scroll region doesn't
X            %     wrap around the end of the physical array
X            Text
X              beginrow numlines add Yindex Text beginrow Yindex
X              inset beginrow sub 1 add getinterval putinterval
X         }{
X            % XXX This should be done as two getinterval/putintervals
X            endrow -1 beginrow numlines add {
X               /i exch def
X               Text i Yindex Text i numlines sub Yindex get put
X            } for
X         } ifelse
X         beginrow 1 beginrow numlines add 1 sub {
X            Text exch Yindex () put
X         } for
X         numlines neg 1 beginrow TextWidth len numlines sub MoveScreenArea
X         1 beginrow TextWidth numlines ClearScreenArea
X      end
X   } def
X
X   /RollAllTextUp   { % numlines => -
X   % --- Scroll the entire Text Array up numlines, adding blank lines at the
X   %     bottom
X      10 dict begin
X         /numlines exch def
X         FlushInputBuffer
X         ClearMySelection
X         1 1 numlines { pop
X            /MapOffset MapOffset 1 add TextHeight mod store
X            Text MapOffset () put
X         } for
X      end
X   } def
X
X   /DrawText { % x y w h => -
X   % --- Draw the text within the specified rectangle
X      10 dict begin
X         /h exch def
X         /w exch def
X         /y exch def
X         /x exch def
X         gsave
X            false setprintermatch
X            Can setcanvas
X            TM setmatrix
X            Font setfont
X            FgColor setcolor
X            % --- Use the clip path to get x clipping
X            x CanY 1 sub w CanHeight 1 add rectpath clip newpath
X            y 1 y h add 1 sub {
X               /i exch def
X               1 i moveto
X%               6 array identmatrix setmatrix % X11/NeWS
X               6 array defaultmatrix setmatrix
X               Text i Yindex get show
X               TM setmatrix
X            } for
X         grestore
X      end
X   } def
X
X   /WriteLines  { % stringarray insertmode? col row => - newcol newrow
X   % Put lines into the text buffer and display them on screen.
X   % stringarray is an array of lines to be displayed. Lines must
X   % contain printable characters only. col,row specify the starting point
X   % of the lines. The col,row of the next available text position are
X   % returned. insertmode? specifies whether to overwrite existing text
X   % or to insert each new line into the existing text.
X      10 dict begin
X         /row exch def
X         /col exch def
X         /insertmode? exch def
X         /lines exch def
X
X         DEBUG {
X            console (WriteLines: row: % col: % numlines: %\n) [row col lines length] fprintf
X            0 1 lines length 1 sub { /i exch def
X               console (%\n) [lines i get] fprintf
X            } for
X            console flushfile
X         } if
X         SupressCaret
X         /WriteInProgress? true store
X         /numlines lines length def
X         % --- Clear the current selection
X         % XXX This should be more selective; only clear if overwriting
X         ClearMySelection
X         % --- Do one line case as fast as possible
X         numlines 1 eq {
X            lines col row WriteOneLine
X         }{
X            % --- Do any text throw-away required, either due to scrolling
X            %     region or exceeding the basic capacity of the Text array.
X            ScrollLimitOn? {
X               /numscroll 0 def
X               % --- Note: No need to do anything if we are completely above
X               %     the scrolling region.
X
X               % --- Are we starting within the scrolling region?
X               row TopScrollLimit ge row BotScrollLimit le and {
X                  % --- Get rid of everything that won't fit in the scroll region
X                  numlines ScrollRegionLength gt {
X                     /lines lines numlines ScrollRegionLength sub
X                        ScrollRegionLength getinterval def
X                     /numlines ScrollRegionLength def
X                     /col 1 def
X                  } if
X                  % --- Determine number of lines to scroll
X                  /numscroll numlines BotScrollLimit row sub sub 1 sub def
X                  % --- Adjust the starting row, if needed
X                  row numlines add 1 sub BotScrollLimit gt {
X		     /row BotScrollLimit numlines 1 sub sub def
X                  } if
X               }{
X                  % --- Are we starting above the scrolling region and extending
X                  %     into it?
X                  row TopScrollLimit lt
X                    row numlines add TopScrollLimit gt and {
X                     % --- Write out the portion of the text that is above the
X                     %     scrolling region by recursively calling WriteLines.
X                     /abovescroll TopScrollLimit row sub def
X                     lines 0 abovescroll getinterval insertmode? col row WriteLines
X                     % --- Get rid of what we just wrote out. This will make us
X                     %     eligable for the "starting within the scrolling region"
X                     %     case.
X                     /lines lines abovescroll numlines abovescroll sub
X                       getinterval def
X                     /row TopScrollLimit def
X                     /col 1 def
X                     /numlines lines length def
X                  } if
X                  % --- Are we starting below the scrolling region?
X                  row BotScrollLimit gt {
X                     % --- Get rid of everything but the last line
X                     /lines lines numlines 1 sub 1 getinterval def
X                     numlines 1 ne {
X                        /col 1 def
X                     } if
X                     /numscroll numlines 1 sub def
X                     /numlines 1 def
X                  } if
X               } ifelse
X               % --- Move existing text up, if necessary
X               numscroll 0 gt {
X                  numscroll TopScrollLimit BotScrollLimit ScrollUp
X               } if
X            }{ % --- No scrolling limits set
X               % --- We can handle a max of TextHeight lines. Throw everything
X               %     else away.
X               numlines TextHeight gt {
X                  /lines lines numlines TextHeight sub
X                  TextHeight getinterval def
X                  /numlines TextHeight def
X               } if
X               % --- Scroll up the text array, if needed
X               /numscroll numlines TextHeight row sub sub 1 sub def
X               numscroll 0 gt {
X                  numscroll RollAllTextUp
X                  /row row numscroll sub def
X                  numscroll 1 1 TextWidth TextHeight MoveScreenArea
X                  col ViewportXdelta sub row ViewportYdelta sub TextWidth
X                    numscroll 1 add ClearScreenArea
X                  % --- If the viewport is off its original position, fill in text
X                  ViewportYdelta 0 ne {
X                     col ViewportXdelta sub row ViewportYdelta sub TextWidth
X                        numscroll 1 add DrawText
X                     % --- Clear out any partial rows or columns
X                     1 CanY CanHeight add TextWidth 1 ClearScreenArea
X                     CanX 1 sub CanY 1 TextHeight ClearScreenArea
X                  } if
X               } if
X            } ifelse
X            col 1 ne {
X               lines 0 1 getinterval col row WriteOneLine /row exch def pop
X               lines 1 numlines 1 sub getinterval row 1 add WriteManyLines
X            }{
X               lines row WriteManyLines
X            } ifelse
X         } ifelse
X         /WriteInProgress? false store
X         % --- Make sure that the newrow return value is within the scrolling limits,
X         %     if appropriate
X         ScrollLimitOn? row BotScrollLimit le and {
X            BotScrollLimit min
X         } if
X      end
X      DelayedCaretMove % --- Must be called outside of this proc's temp dict
X   } def
X
X   /WriteOneLine  { % stringarray col row => - newcol newrow
X   % Put one line into the text buffer and display it on screen.
X   % stringarray is an array containing a single line of text.
X   % WriteOneLine makes use of the InputBuffer optimization.
X   % col,row specify the starting point of the lines. The col,row
X   % of the next available text position are returned.
X      10 dict begin
X         /row exch def
X         /col exch def
X         /s exch 0 get def
X
X         DEBUG {
X            console (WriteOneLine row: % col: % slen: %\n) [row col s length] fprintf
X            console (%\n) [s] fprintf
X            console flushfile
X         } if
X         /slen s length def
X         % --- Set the input buffer to this line if it isn't already there
X         row InputBufferLine ne {
X            FlushInputBuffer
X            % --- Copy the existing Text string into InputBuffer
X            /oldline Text row Yindex get def
X            oldline InputBuffer copy pop
X            /InputBufferLength oldline length store
X            /InputBufferLine row store
X         } if
X         insertmode? {
X            % --- Make sure we aren't exceeding the size of the input buffer
X            slen col add slen InputBufferLength add max InputBuffer length gt {
X               % --- If we are too big, simply grow the input buffer to accomodate!
X               %     Ain't automatic garbage collection wonderful...
X               /InputBuffer slen col add string store
X               Text row Yindex get InputBuffer copy pop
X            } if
X            % --- Move old Text over if necessary
X            col InputBufferLength le {
X               InputBuffer col slen add Xindex
X                  InputBuffer col Xindex InputBufferLength col sub 1 add getinterval
X               putinterval
X               /InputBufferLength InputBufferLength slen add store
X            }{
X               /InputBufferLength col slen add 1 sub store
X            } ifelse
X            InputBufferLength TextWidth gt {
X               /TextWidth InputBufferLength store
X            } if
X            % --- Put insert string in
X            InputBuffer col Xindex s putinterval
X         }{
X            % --- Make sure we aren't exceeding the size of the input buffer
X            slen col add InputBuffer length gt {
X               % --- If we are too big, simply grow the input buffer to accomodate!
X               %     Ain't automatic garbage collection wonderful...
X               /InputBuffer slen col add string store
X               Text row Yindex get InputBuffer copy pop
X            } if
X            % --- Slam the new text into the InputBuffer
X            InputBuffer col Xindex s putinterval
X            /InputBufferLength InputBufferLength col slen add 1 sub max store
X         } ifelse
X         % --- Update the text array with a substring of InputBuffer
X         Text row Yindex InputBuffer 0 InputBufferLength getinterval put
X         InputBufferLength TextWidth gt {
X            /TextWidth InputBufferLength store
X         } if
X         % --- Paint the screen
X         insertmode? {
X            col row InputBufferLength 1 ClearScreenArea
X            col row InputBufferLength 1 DrawText
X         }{
X            col row slen 1 ClearScreenArea
X            col row slen 1 DrawText
X         } ifelse
X         % --- Remove any partial rows or columns
X         ViewportXdelta 0 ne ViewportYdelta 0 ne or {
X            1 CanY CanHeight add TextWidth 1 ClearScreenArea
X            CanX 1 sub CanY 1 TextHeight ClearScreenArea
X         } if
X         % --- Return new row,col
X         col slen add row
X      end
X   } def
X
X   /WriteManyLines  { % stringarray row => - newcol newrow
X   % Put one line into the text buffer and display it on screen.
X   % stringarray is an array containing a single line of text.
X   % row specifies the starting point of the lines. The col,row
X   % of the next available text position are returned.
X      20 dict begin
X         /row exch def
X         /lines exch def
X
X         DEBUG {
X            console (WriteManyLines: row: % col: % numlines: %\n) [row col lines length] fprintf
X            0 1 lines length 1 sub { /i exch def
X               console (%\n) [lines i get] fprintf
X            } for
X            console flushfile
X         } if
X         FlushInputBuffer
X         /endrow row def
X         lines {
X	    /s exch def
X            /slen s length def
X            /oldline Text endrow Yindex get def
X            /oldlen oldline length def
X            slen TextWidth gt {
X               /TextWidth slen store
X            } if
X            insertmode? {
X               oldlen 0 eq {
X                  Text endrow Yindex s put
X               }{
X                  Text endrow Yindex s oldline append put
X               } ifelse
X            }{
X               slen oldlen ge {
X                  Text endrow Yindex s put
X               }{
X                  oldline 0 s putinterval
X               } ifelse
X            } ifelse
X            /endrow endrow 1 add def
X            /col slen 1 add def
X         } forall
X         % --- Clear the changed screen area and draw the new text
X         1 row TextWidth endrow row sub 1 add ClearScreenArea
X         1 row TextWidth endrow row sub 1 add DrawText
X         % --- Remove any partial rows or columns
X         ViewportXdelta 0 ne ViewportYdelta 0 ne or {
X            1 CanY CanHeight add TextWidth 1 ClearScreenArea
X            CanX 1 sub CanY 1 TextHeight ClearScreenArea
X         } if
X         % --- Return values
X         col endrow 1 sub
X      end
X   } def
X
X   /CreateCaret {   %   - => -
X   % --- Create, shape, and color the caret canvas
X       CaretColor null eq {
X          ColorDisplay?
X             {/CaretColor DefaultColorCaret store}
X             {/CaretColor DefaultMonoCaret store} ifelse
X       } if
X       gsave
X          Can setcanvas
X          /Caret Can newcanvas store
X          Caret begin
X              /Transparent false def
X              Can /Retained get {
X% REMIND:
X% There doesn't seem to be any reason to make the cursor retained.
X% Let's try taking this out some time...
X%                 /Retained true def
X% HURRAY! IT WORKED! It even made the 386i X11/NeWS beta 2 server stop dumping!
X                 /Retained false def
X              }{
X                 /SaveBehind true def
X              } ifelse
X   	      /EventsConsumed /MatchedEvents def
X          end
X          ShapeCaret
X       grestore
X   } def
X
X   /ShapeCaret {   %   - => -
X   % --- Shape the caret canvas from a proc in the CaretShapeDict
X       gsave
X%        framebuffer setcanvas % ???
X%	matrix defaultmatrix setmatrix % ???
X	Can setcanvas
X   	% ---Set up x,y arguments to caret shape proc
X   	PixColWidth PixRowHeight
X   	% ---Get the caret shape proc and execute it
X   	CaretShapeDict CaretShape get exec
X        PixColWidth PixRowHeight neg scale
X        0 1 translate
X   	Caret reshapecanvas
X       grestore
X   } def
X
X   /MapCaret {   %   - => -
X   % --- Make the caret visible and color it
X      gsave
X    	 Caret mapcanvas
X   	 Caret setcanvas
X         CaretInactive? {
X% /mapcaret dbgbreak
X% CORE DUMPS X11/NeWS beta 2 386i:
X   	    DefaultInactiveColor fillcanvas
X         }{
X   	    CaretColor fillcanvas
X         } ifelse
X      grestore
X   } def
X
X   /UnMapCaret {   %   - => -
X   % --- Make the caret invisible
X       Caret unmapcanvas
X   } def
X
X   /MoveCaret { % - => -
X      gsave
X         Caret unmapcanvas
X         Caret setcanvas
X         CaretX ViewportXdelta add CaretY ViewportYdelta add
X         movecanvas
X         Caret mapcanvas
X      grestore
X   } def
X
X   /InactivateCaret { % - => -
X   % --- Shade the caret with the inactive color and stop any blinking
X   10 dict begin
X      /CaretInactive? true store
X      CaretOn? {
X         gsave
X            Caret mapcanvas
X            Caret setcanvas
X% Bombs X11/NeWS beta 2 on 386i: (sh_386_fill_shape, fillscans)
X            DefaultInactiveColor fillcanvas
X         grestore
X      } if
X   end
X   } def
X
X   /ReactivateCaret { % - => -
X   % --- Set caret back to normal
X   10 dict begin
X      /CaretInactive? false store
X      CaretOn? {
X         gsave
X            Caret mapcanvas
X            Caret setcanvas
X            CaretColor fillcanvas
X         grestore
X      } if
X   end
X   } def
X
X   /SupressCaret { % - => -
X   % --- Temporarily turn the caret off
X   10 dict begin
X      CaretOn? {
X         /CaretSupressed? true store
X         UnMapCaret
X      } if
X   end
X   } def
X
X   /UnSupressCaret { % - => -
X   % --- Turn the caret back on
X   10 dict begin
X      CaretOn? {
X         /CaretSupressed? false store
X         MapCaret
X      } if
X   end
X   } def
X
X   /DelayedCaretMove { % - => -
X   % --- Move the caret after waiting CaretDelayTime seconds,
X   %     but only if a write or another delayed caret move is
X   %     not in progress
X   %     Note: This proc must be called with the class instance dictionary
X   %     being the first thing on the dict stack, since it forks a process
X   %     that change instance variables.
X      CaretOn? {
X         % --- Update the time that the caret move will actually be done
X         /NextMoveTime currenttime 1 60 div CaretDelayTime mul add store
X         % --- Only fork a timer if one isn't already going
X         DelayedMoveProc null eq {
X            % --- Fork the move timer
X            /DelayedMoveProc {
X               % Go to sleep, checking NextMoveTime each time we awaken
X               {
X                  NextMoveTime currenttime sub sleep
X                  NextMoveTime currenttime le {
X	             exit
X	          } if
X               } loop
X               % --- If there is no write in progress then move the caret and
X               %     turn it on
X               WriteInProgress? not {
X                  /CaretSupressed? false store
X                  MoveCaret
X                  MapCaret
X               } if
X               /DelayedMoveProc null store
X            } fork store
X         } if
X      } if
X   } def
X
X%   /DrawSelectionText { % x y y1 => -
X%   % --- Draw text onto the selection canvas
X%      10 dict begin
X%         /y1 exch def
X%         /y exch def
X%         /x exch def
X%         gsave
X%            false setprintermatch
X%            SelectionCan setcanvas
X%            FgColor fillcanvas
X%            FontDescentTM setmatrix
X%            x 1 sub neg TextHeight y1 sub translate
X%            /SelectTM 6 array currentmatrix def
X%            Font setfont
X%            BgColor setcolor
X%            /j 1 def
X%            y 1 y1 {
X%               /i exch def
X%               1 i moveto
X%               6 array identmatrix setmatrix
X%               Text i Yindex get show
X%               SelectTM setmatrix
X%               /j j 1 add def
X%            } for
X%         grestore
X%      end
X%    } def
X
X   /DrawSelection { % state => -
X   % --- Make the selection area visible or invisible, depending on state.
X      10 dict begin
X         /state exch def
X         %state {
X         %    SelectionPath null ne {
X         %       gsave
X         %          6 array identmatrix setmatrix
X         %          SelectionPath setpath
X         %          SelectionCan reshapecanvas
X         %          SelectionY SelectionY1 lt {
X         %             1 SelectionY SelectionY1 DrawSelectionText
X         %          } if
X         %          SelectionY SelectionY1 gt {
X         %             1 SelectionY1 SelectionY DrawSelectionText
X         %          } if
X         %          SelectionY SelectionY1 eq {
X         %             SelectionX SelectionY1 SelectionY DrawSelectionText
X         %          } if
X         %          SelectionCan mapcanvas
X         %          /SelectionOn? true store
X         %       grestore
X         %    } if
X         %}{ % --- state = off
X         %   SelectionCan unmapcanvas
X         %   /SelectionOn? false store
X         %} ifelse
X         % --- XXX Use xor for now; SelectionCanvas in the future...
X         gsave
X            SelectionPath null ne SelectionOn? state xor and {
X               Can setcanvas
X               TM setmatrix
X               5 setrasteropcode
X               SelectionPath setpath
X               fill
X               /SelectionOn? state store
X            } if
X         grestore
X      end
X   } def
X
X   /ClearMySelection { % - => -
X   % --- Clear any selection I might have in the system selection mechanism
X   %     and on my screen.
X      10 dict begin
X         SelectionOn? {
X               false DrawSelection
X               /SelectionPath null store
X         } if
X         /seldict /PrimarySelection getselection def
X         seldict null ne {
X            seldict XNeWS? /Holder /Canvas ifelse % not defined in X11/NeWS
X	    get Can eq {
X%               Selections /PrimarySelection null put % broke in X11/NeWS
X               /PrimarySelection clearselection
X            } if
X         } if
X      end
X   } def
X
X   /SendClearSelection { % - => -
X   % --- Clear anyone else's Primary selection
X      10 dict begin
X         /seldict /PrimarySelection getselection def
X         seldict null ne {
X            seldict XNeWS? /Holder /Canvas ifelse % not defined in X11/NeWS
X	    get Can ne {
X               /PrimarySelection clearselection
X            } if
X         } if
X      end
X   } def
X
X   /ExtendSelection { % - => -
X   % --- Draw the selection bounding outline
X      10 dict begin
X       gsave
X         FontDescentTM setmatrix
X         /l Text SelectionY1 Yindex get length 2 add def
X         SelectionX1 l gt {
X            /SelectionX1 l def
X         } if
X         SelectionY SelectionY1 eq {
X            SelectionX SelectionY SelectionX1 SelectionY1 1 sub
X            points2rect rectpath
X         }{
X            SelectionY SelectionY1 gt {
X               /y SelectionY1 def /x SelectionX1 def
X               /y1 SelectionY def /x1 SelectionX def
X            }{
X               /y SelectionY def /x SelectionX def
X               /y1 SelectionY1 def /x1 SelectionX1 def
X            } ifelse
X            1 y moveto
X            x y lineto
X            0 -1 rlineto
X            /l Text y Yindex get length 2 add def
X            l y 1 sub lineto
X            0 1 rlineto
X            /y y 1 add def
X            y 1 y1 1 sub {
X               /i exch def
X               /l Text i Yindex get length 2 add def
X               l i 1 sub lineto
X               l i lineto
X            } for
X            x1 y1 1 sub lineto
X            x1 y1 lineto
X            1 y1 lineto
X            closepath
X         } ifelse
X         /SelectionPath currentpath store
X	 0 setlinewidth % Thick lines look funky with xor, but it's a bug...
X         stroke
X        grestore
X       end
X   } def
X
X   /GetSelection { % - => string
X   % --- Returns the text of the current selection
X      10 dict begin
X         SelectionPath null eq {
X            ()
X         }{
X            % --- We always want y <= y1, no matter what direction the selection
X            %     was done in
X            SelectionY SelectionY1 lt {
X               /y SelectionY def /x SelectionX def
X               /y1 SelectionY1 def /x1 SelectionX1 1 sub def
X            } if
X            SelectionY SelectionY1 gt {
X               /y SelectionY1 def /x SelectionX1 def
X               /y1 SelectionY def /x1 SelectionX 1 sub def
X            } if
X            SelectionY SelectionY1 eq {
X               /y SelectionY def /x SelectionX def
X               /y1 SelectionY1 def /x1 SelectionX1 1 sub def
X               % --- If we are on the same line, we want x <= x1
X               x x1 gt {
X                  x
X                  /x x1 1 add def
X                  /x1 exch 1 sub def
X               } if
X            } if
X            % --- Make a string that is at least the right size
X            /slen 0 def
X            y 1 y1 {/i exch def /slen Text i Yindex get length slen add 1 add def} for
X            /s slen string def
X            /sptr 0 def
X            % --- Get the first line of the selection text
X            /s1 Text y Yindex get def
X            /l s1 length def
X            % --- Index into it by x (add a LF if x > linelength)
X            x l gt {
X               s sptr LF put
X               /sptr sptr 1 add def
X            }{
X               /s1 s1 x Xindex l x sub 1 add getinterval def
X               s sptr s1 putinterval
X               /sptr sptr s1 length add def
X            } ifelse
X            % --- Check for a single line selection
X            y y1 eq {
X               % --- Clip the line at x1 (add a LF if x1 > linelength)
X               x1 l gt {
X                  % --- Make sure we don't put in two LF's
X                  x l le {
X                     s sptr LF put
X                     /sptr sptr 1 add def
X                  } if
X               }{
X                  /sptr x1 x sub 1 add def
X               } ifelse
X            }{ % --- Multi-line selection
X               % --- Put LF after first line if needed
X               x l le {
X                  s sptr LF put
X                  /sptr sptr 1 add def
X               } if
X               y 1 add 1 y1 {
X                  /i exch def
X                  % --- Get the i'th line
X                  /l Text i Yindex get length def
X                  /s1 Text i Yindex get def
X                  % --- Check if this is the last line
X                  i y1 eq {
X                     x1 l gt {
X                        s sptr s1 putinterval
X                        /sptr sptr l add def
X                        s sptr LF put
X                        /sptr sptr 1 add def
X                     }{
X                        /s1 s1 0 x1 getinterval def
X                        s sptr s1 putinterval
X                        /sptr sptr s1 length add def
X                     } ifelse
X                  }{
X                     s sptr s1 putinterval
X                     /sptr sptr l add def
X                     s sptr LF put
X                     /sptr sptr 1 add def
X                  } ifelse
X               } for
X            } ifelse
X            s 0 sptr getinterval
X         } ifelse
X   } def
X
X% ----------------------------- New Methods -----------------------------------
X
X   /changefont	{ % fname fheight - => -
X   % --- Change the current font and point size. Either fname or fheight
X   %     may be null, in which case they are ignored.
X   10 dict begin
X      /fheight exch def
X      /fname exch def
X      fheight null ne {
X         /FontHeight fheight store
X         % --- Check for minimum visibility
X         FontHeight 6 lt {
X            /FontHeight 6 store
X         } def
X      } if
X      fname null ne {
X         /FontName fname store
X      } if
X      InitFont
X      false Reshape
X      1 1 TextWidth TextHeight DrawText
X      CaretOn? {
X	 ShapeCaret
X         MapCaret
X         MoveCaret
X      } if
X      /ResizeCallback self send
X   end
X   } def
X
X   /writelines {  % arrayofstrings insertmode? col row => -
X   % --- Write an array of strings, starting the first string at col,row
X   %     with subsequent strings going at 1,row+1 1,row+2 etc. insertmode?
X   %     specifies whether the new lines will overwrite existing text or
X   %     be inserted at the specified location.
X      BaseY add
X      WriteLines pop pop
X      pause
X   } def
X
X   /writeatcaret {  % arrayofstrings insertmode? => -
X   % --- Similar to writelines, except start at the current caret location. The
X   %     caret is moved to the next available character position when the write is
X   %     done.
X      CaretX CaretY WriteLines
X      /CaretY exch store
X      /CaretX exch store
X      pause
X   } def
X
X   /deletestring { % length col row => -
X   % --- Delete a string starting at col,row for length characters.
X   %     length must be 0 or a positive integer.
X      BaseY add
X      10 dict begin
X         /row exch def
X         /col exch def
X         /len exch def
X
X         % --- Set the input buffer to this line if it isn't already there
X         row InputBufferLine ne {
X            FlushInputBuffer
X            % --- Copy the existing Text string into InputBuffer
X            /oldline Text row Yindex get def
X            /oldlength oldline length def
X            oldline InputBuffer copy pop
X            /InputBufferLine row store
X            /InputBufferLength oldlength store
X          }{
X            /oldlength InputBufferLength def
X         } ifelse
X         col InputBufferLength le {
X            % --- Move old text over
X            InputBuffer col Xindex
X               InputBuffer col len add Xindex InputBufferLength len add getinterval
X            putinterval
X            % --- Update line length
X            /InputBufferLength InputBufferLength len sub col 1 sub max store
X         } if
X         % --- Update the Text array
X         Text row Yindex InputBuffer 0 InputBufferLength getinterval put
X         % --- Update display
X         col row oldlength 1 ClearScreenArea
X         col row oldlength 1 DrawText
X       end
X   } def
X
X   /insertline { % numlines row => -
X   % --- Insert numlines blank lines, starting at line row.
X   %     numlines must be 0 or a positive integer
X      BaseY add
X      10 dict begin
X         /row exch def
X         /numlines exch def
X         numlines row TextHeight ScrollDown
X      end
X   } def
X
X   /deleteline { % numlines row => -
X   % --- Delete numlines lines, starting at line row.
X   %     numlines must be 0 or a positive integer
X      BaseY add
X      10 dict begin
X         /row exch def
X         /numlines exch def
X         numlines row TextHeight ScrollUp
X      end
X   } def
X
X   /setscrollinglimits { % toprow bottomrow => -
X   % --- Sets the scrolling limits for the TextCanvas. All up or down scrolling
X   %     will be limited to this region instead of affecting the entire Text
X   %     canvas. When scrolling limits are set, those methods which can
X   %     trigger scrolling (writelines, writeatcaret, movecaretdelta) will
X   %     only cause scrolling if they affect lines within the scrolling region.
X   %     Any scrolling that is initiated will only move lines within the
X   %     scrolling region.
X      /BotScrollLimit exch BaseY add def
X      /TopScrollLimit exch BaseY add def
X      /ScrollRegionLength BotScrollLimit TopScrollLimit sub 1 add  def
X      /ScrollLimitOn? true def
X   } def
X
X   /removescrollinglimits { % - => -
X   % --- Removes any scrolling bounds set by setscrollinglimits.
X      /BotScrollLimit TextHeight def
X      /TopScrollLimit CanY def
X      /ScrollRegionLength BotScrollLimit TopScrollLimit sub 1 add  def
X      /ScrollLimitOn? false def
X   } def
X
X   /clearviewport { % - => -
X   % --- Clear the text and screen area of the base viewport
X      ScrollLimitOn? {
X         CanHeight BaseY 1 add BaseY CanHeight add ScrollUp
X      }{
X         CanHeight RollAllTextUp
X         1 BaseY 1 add TextWidth CanHeight ClearScreenArea
X      } ifelse
X   } def
X
X   /flashviewport { % - => -
X   % --- Flash the contents of the viewport (visible bell)
X      gsave
X         Can setcanvas
X         initclip
X         clipcanvaspath
X         5 setrasteropcode
X         fill
X         clipcanvaspath
X         fill
X      grestore
X   } def
X
X   /moveviewport { %x y => -
X   % --- Move the viewport to another part of the underlying Text array.
X   %     x and y must be between 0 and 1. This represents a percentage of the
X   %     current total width or height of the Text array. Either argument
X   %     can be null, in which case it is ignored.
X      10 dict begin
X         SupressCaret
X         dup null ne {
X            /newY exch TextHeight CanHeight sub mul 1 add round def
X            newY 1 lt {
X               /newY 1 def
X            } if
X            /ydelta CanY newY sub def
X            ClearMySelection
X         }{
X            /newY exch def
X            /ydelta 0 def
X         } ifelse
X         dup null ne {
X            /newX exch TextWidth CanWidth sub mul 1 add round def
X            newX 1 lt {
X               /newX 1 def
X            } if
X            /xdelta CanX newX sub def
X            ClearMySelection
X         }{
X            /newX exch def
X            /xdelta 0 def
X         } ifelse
X         gsave
X            Can setcanvas
X	    FontDescentTM setmatrix
X	    CanX CanY 1 sub CanWidth CanHeight 1 add rectpath
X            xdelta ydelta copyarea
X            xdelta ydelta translate
X            /FontDescentTM 6 array currentmatrix store
X            % --- XXX translate doesn't work with a matrix operand yet
X            TM setmatrix
X            xdelta ydelta translate
X            /TM 6 array currentmatrix store
X         grestore
X         xdelta 0 ne {
X            /CanX newX store
X            xdelta 0 gt {
X               CanX CanY xdelta CanHeight ClearScreenArea
X               CanX CanY xdelta CanHeight DrawText
X            }{
X               CanX CanWidth add xdelta add CanY
X                  xdelta neg CanHeight ClearScreenArea
X               CanX CanWidth add xdelta add CanY
X                  xdelta neg CanHeight DrawText
X               % --- Clear out column 0
X               CanX 1 sub CanY 1 TextHeight ClearScreenArea
X            } ifelse
X         } if
X         ydelta 0 ne {
X            /CanY newY store
X            ydelta 0 gt {
X               CanX CanY CanWidth ydelta 1 add ClearScreenArea
X               CanX CanY CanWidth ydelta 1 add DrawText
X            }{
X               CanX CanY CanHeight add ydelta add
X                  CanWidth ydelta neg ClearScreenArea
X               CanX CanY CanHeight add ydelta add
X                  CanWidth ydelta neg DrawText
X            } ifelse
X         } if
X         CanX CanY CanHeight add CanWidth 1 ClearScreenArea
X         /ViewportXdelta ViewportXdelta xdelta add store
X         /ViewportYdelta ViewportYdelta ydelta add store
X         MoveCaret
X         UnSupressCaret
X      end
X   } def
X
X   /getviewportsize { % - => col rows xpixels ypixels
X   % --- Return the number of columns, rows, pixel height and width of
X   %     the viewport.
X      CanWidth CanHeight CanPixWidth CanPixHeight
X   } def
X
X   /getlinelength { % row => length
X   % --- Return the current length of the line at row.
X      BaseY add
X      Text exch Yindex get
X      length
X   } def
X
X   /calcarea { % pixwidth pixheight => numcols numrows
X   % --- Returns the number of rows and columns that will fit into the pixel
X   %     area specified by pixwidth and pixheight, given the current Font and
X   %     point size.
X      10 dict begin
X         /pixheight exch def
X         /pixwidth exch def
X         % --- Compute numcols
X         pixwidth PixColWidth idiv
X         % --- Compute numrows
X         pixheight PixRowHeight idiv 1 add
X      end
X   } def
X
X   /calcpixarea { % numcols numrows => pixwidth pixheight
X   % --- Returns the minimum pixel area required to display numrows and numcols,
X   %     given the current Font and point size.
X      10 dict begin
X         /numcols exch def
X         /numrows exch def
X         % --- Compute pixwidth
X         numcols PixColWidth mul
X         % --- Compute pixheight
X         numrows PixRowHeight mul 1 sub
X      end
X   } def
X
X   /oncaret {   %   - => -
X   % --- Turn the caret on.
X       /CaretOn? true def
X       MapCaret
X       MoveCaret
X   } def
X
X   /offcaret {   %   - => -
X   % --- Turn the caret off.
X       UnMapCaret
X       /CaretOn? false def
X   } def
X
X   /movecaret { % col row => -
X   % --- Move the caret to an absolute position. col and row are integers. Scrolling is
X   %     never triggered.
X       /CaretY exch BaseY add def
X       /CaretX exch def
X       CaretX TextWidth gt {/TextWidth CaretX store} if
X       MoveCaret
X   } def
X
X   /movecaretdelta { % deltax deltay => -
X   % --- Move the caret relative to its current position. deltax and deltay must be
X   %     integers (negatives allowed). Scrolling is triggered if deltay moves the caret
X   %     outside of the scrolling limits. If no scrolling limits are set, scrolling is
X   %     triggered if deltay moves the caret outside of the original viewport region.
X       10 dict begin
X          /deltay exch def
X          /deltax exch def
X          /CaretY CaretY deltay add store
X          /CaretX CaretX deltax add store
X          CaretY TopScrollLimit lt {
X             TopScrollLimit CaretY sub TopScrollLimit BotScrollLimit ScrollDown
X             /CaretY TopScrollLimit store
X          } if
X          CaretY BotScrollLimit gt {
X             CaretY BotScrollLimit sub TopScrollLimit BotScrollLimit ScrollUp
X             /CaretY TextHeight store
X          } if
X          CaretX 1 lt {/CaretX 1 store} if
X          CaretX TextWidth gt {/TextWidth CaretX store} if
X          MoveCaret
X       end
X   } def
X
X   /setcaretblink {   %   blink-rate duty-cycle => -
X   % --- Set the caret blink rate and the blink duty cycle. blink-rate is
X   %     in seconds and represents a complete on/off cycle. duty-cycle is
X   %     between 0 and 1, and represents the percentage of on time.
X       dup null ne {
X          /CaretDutyCycle exch def
X       }{
X          pop
X       } ifelse
X       dup null ne {
X          dup 0 ne {
X             /CaretBlinkTime exch def
X             /CaretBlinkEnabled? true def
X          }{
X	     % --- Disable caret, but keep blink events going at a
X             %     2 second rate
X	     pop
X             /CaretBlinkTime 2 def
X             /CaretBlinkEnabled? false def
X             CaretOn? {MapCaret} if
X          } ifelse
X       }{
X          pop
X       } ifelse
X   } def
X
X   /setcaretcolor {   %   color => -
X   % --- Set the current caret color. color is a color object.
X       /CaretColor exch def
X       CaretOn? {MapCaret} if
X   } def
X
X   /setcaretshape {  % shapename => successful?
X   % --- Set the caret shape. shapename should be an entry in the CaretShapeDict.
X   %     Return a boolean that tells whether shapename was found.
X      dup CaretShapeDict exch known {
X         /CaretShape exch def
X         Caret null ne {ShapeCaret MoveCaret} if
X         true
X      } {
X         pop pop
X         false
X      } ifelse
X   } def
X
X   /getcaretpos {   % - => col row
X   % --- Return the current caret position
X       CaretX
X       CaretY BaseY sub
X   } def
X
X   /setbgcolor { % color => -
X   % --- Set the current canvas background color
X      ClearMySelection
X      /BgColor exch def
X   } def
X
X   /setfgcolor { % color => -
X   % --- Set the current text color
X      ClearMySelection
X      /FgColor exch def
X   } def
X
X   /fixdamage { % - => -
X   % --- Damage handler; goes in the PaintClient window callback routine
X         BgColor fillcanvas
X         CanX CanY CanWidth CanHeight DrawText
X   } def
X
X   /new { % numrows can => object
X   % --- Create a new instance of the TextCanvas. numrows is the number
X   %     of lines to be allocated in the Text array; it is fixed for
X   %     the life of the instance. can is the viewport canvas.
X       /new super send begin
X	  /Can exch def
X	  /TextHeight exch def
X% Here's an attempt to keep the 386i X11/NeWS beta 2 server from core dumping.
X%Can /Transparent false put
X          Can /Retained true put % XXX - Non-retained will work, but NeWS sometimes
X          			 % reports more damage than has actually occurred,
X				 % so going non-retained can be very costly
X          gsave
X             % --- Determine canvas pixel width and height
X             Can setcanvas
X	     initclip clipcanvaspath pathbbox  % llx lly urx ury
X             points2rect	  	       % x y w h
X          grestore
X	  /CanPixHeight exch def
X	  /CanPixWidth exch def
X	  /CanPixY exch def
X	  /CanPixX exch def
X          InitFont
X          true Reshape
X          currentdict
X       end
X   } def
X
X   /reshape { % - => -
X   % --- This method must be called whenever the viewport canvas has changed
X   %     size. It updates the number of rows and columns in the TextCanvas,
X   %     repositions the caret to be as close to its old position as possible,
X   %     resets the scrolling region, and moves the viewport to its base position.
X      gsave
X         % --- Determine the new pixel width and height
X         Can setcanvas
X         initclip clipcanvaspath pathbbox  % llx lly urx ury
X         points2rect			   % x y w h
X      grestore
X      /CanPixHeight exch def
X      /CanPixWidth exch def
X      /CanPixY exch def
X      /CanPixX exch def
X      false Reshape
X      /ResizeCallback self send
X   } def
X
X   /destroy { % - => -
X       mark {
X         KeyboardInterest Can revokekbdinterests
X	 MoreInterests { revokeinterest } forall
X       } stopped cleartomark
X       EventMgr null ne {
X          EventMgr killprocess
X       } if
X       MouseDragEventMgr null ne {
X          MouseDragEventMgr killprocess
X       } if
X   } def
X
Xclassend def
Xend % systemdict
X%} if % /TextCanvas known not...
X
//go.sysin dd *
if [ `wc -c < textcan.ps` != 83120 ]; then
	made=false
	echo error transmitting textcan.ps --
	echo length should be 83120, not `wc -c < textcan.ps`
else
	made=true
fi
if $made; then
	chmod 664 textcan.ps
	echo -n '	'; ls -ld textcan.ps
fi
echo Extracting overlay.ps
sed 's/^X//' <<'//go.sysin dd *' >overlay.ps
X%!
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X% Class OverlayWindow
X% Copyright (C) 1989.
X% By Don Hopkins. (don@brillig.umd.edu)
X% All rights reserved.
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X%  This program is provided for UNRESTRICTED use provided that this
X%  copyright message is preserved on all copies and derivative works.
X%  This is provided without any warranty. No author or distributor
X%  accepts any responsibility whatsoever to any person or any entity
X%  with respect to any loss or damage caused or alleged to be caused
X%  directly or indirectly by this program. This includes, but is not
X%  limited to, any interruption of service, loss of business, loss of
X%  information, loss of anticipated profits, core dumps, abuses of the
X%  virtual memory system, or any consequential or incidental damages
X%  resulting from the use of this program.
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X% Overlay plane compatibility hack for cg4 frame buffer.
X% This is a nebulous layer abstracted from a messy program, to make it run
X% on generic NeWS servers. It should be rethought and rewritten. Repent!
X%
X% Requires the devices /dev/cgfour0, /dev/cgfour0_ovl, and /dev/cgfour0_ove
X% (which can all be major 39 minor 0, or whatever), and the following patch
X% to the NeWS 1.1 server sources (but X11/NeWS doesn't need to be patched!),
X% in order to take advantage of a cg4 under NeWS 1.1 (Otherwise it falls back
X% to using exclusive-or).
X%
X% Put the flag -DCG4_ENABLE_HACK into COPTS in the top level server Makefile.
X% Make the following patch to the file SUN/src/server/dev/sunw/pixrectint.c:
X% In function cg4_make:
X% Replace the block starting with the following comment:
X% 	/* set up pixrect initial state */
X% 	{
X% #ifdef CG4_ENABLE_HACK
X% 		int initplanes, initfb = CG4_INITFB;
X% 		extern char *sun_fb_name;
X% 		char *index();
X% 		int len = strlen (sun_fb_name);
X%
X% 		/* Special file names get overlay and enable planes */
X% 		if (index(sun_fb_name, '_') != NULL) {
X% 		    if (sun_fb_name[len-1] == 'l') /* cgfour0_ovl */
X% 			initfb = 0; /* overlay plane */
X% 		    else if (sun_fb_name[len-1] == 'e') /* cgfour0_ove */
X% 			initfb = 1; /* enable plane */
X% 		    else initfb = 2; /* color plane */
X% 		}
X%
X% 		initplanes =
X% 			PIX_GROUP(fbdesc[initfb].group) |
X% 			fbdesc[initfb].allplanes;
X% #else !CG4_ENABLE_HACK
X% 		int initplanes =
X% 			PIX_GROUP(fbdesc[CG4_INITFB].group) |
X% 			fbdesc[CG4_INITFB].allplanes;
X% #endif !CG4_ENABLE_HACK
X%
X% 		(void) cg4_putattributes(pr, &initplanes);
X% 	}
X%
X% Damn damn damn! X11/NeWS Version 1.0 FCS on a cg4 can open up the
X% enable plane, but there's a bug that trashes the enable plane color map,
X% so we can draw in gray scales but we can't draw in white (black?).
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
Xsystemdict begin
X
Xsystemdict /XNeWS? known not {
X  systemdict /XNeWS? false put
X} if
X
X/overlay-dev (/dev/cgfour0_ovl) def
X/enable-dev (/dev/cgfour0_ove) def
X/color-dev (/dev/cgfour0) def
X
Xmark
Xsystemdict /fb_overlay known not {
X  /fb_overlay null def  /fb_enable null def  /fb_color null def
X  /mono? framebuffer /Color get not def
X  systemdict /no_funny_stuff known
X  XNeWS? or % disabled, because of pre-fsc X11/NeWS...
X  { true } {
X    {
X      /fb_overlay overlay-dev createdevice store
X      %fb_overlay /Retained true put
X      /fb_enable enable-dev createdevice store
X      XNeWS? {
X% this-is-currently-disabled % delete this line to re-enable, but it don't work
X	% Attempt to work around bug with X11/NeWS pre-fcs:
X	% The color map of the enable plane is bogus.
X	% 1 setgray results in black instead of white.
X	% All other setgrays < 1 come out the right color.
X	/fb_enable fb_enable
X{
X	fb_overlay begin
X	  Visual Colormap
X	end
X} pop
X	newcanvas store
X	framebuffer setcanvas
X	clippath fb_enable reshapecanvas
X	fb_enable /Transparent false put
X	fb_enable /Mapped true put
X      } if
X      fb_enable /Retained true put % is there any damage?
X      % if so, have event mgr clean it up instead of retaining?
X      /fb_color color-dev createdevice store
X      % createdevice bug: ignores file name (MacNeWS)
X      fb_enable /Color get not fb_color /Color get and {
X        gsave
X	  fb_enable setcanvas
X	  mono? 0 1 ifelse fillcanvas
X        grestore
X      } {
X	/fb_overlay null store
X	/fb_enable null store
X	/fb_color null store
X	that-aint-no-overlay-plane!
X      } ifelse
X    } errored
X  } ifelse
X  /cg4? exch not def
X  cg4? not {
X    systemdict /fb_overlay undef
X    systemdict /fb_enable undef
X    systemdict /fb_color undef
X  } if
X} if
Xcleartomark
X
X/OverlayWindow DefaultWindow
Xdictbegin
X  /EnableCanvas null def
X  /EnableOverlay null def
X  /OverlayCanvas null def
X  /ColorCanvas null def
X  /TrackCanvas null def
X  /OtherCanvas null def
X  /HiliteCanvas null def
X  /SpriteCanvas null def
X  /SpriteMaskCanvas null def
X  /BubbleRadius 32 def
X  /LastX 0 def /LastY 0 def
X  /LastW 0 def /LastH 0 def
X  /InitialOverlayGray 0 def
X  /InitialEnableGray 1 def
Xdictend
Xclassbegin
X
Xcg4? { % cg4
X
X  /ShapeClientCanvas {
X    /ShapeClientCanvas super send
X      gsave
X	ClientCanvas setcanvas
X        /nouse /nouse_m ClientCanvas setstandardcursor
X	clippath OverlayCanvas reshapecanvas
X	clippath EnableCanvas reshapecanvas
X	EnableCanvas setcanvas
X	InitialEnableGray fillcanvas
X	OverlayCanvas setcanvas
X	InitialOverlayGray fillcanvas
X	ClientCanvas setcanvas
X	ClientWidth 2 div ClientHeight 2 div
X        SpriteShape
X        SpriteMaskCanvas reshapecanvas
X      grestore
X      DrawSpriteMask
X  } def
X
X  /UpdateSprite { % x y => -
X    gsave
X      SpriteMaskCanvas setcanvas
X      XNeWS? not {
X        SpriteHotY
X        dup add sub
X      } if % ARGH!
X      movecanvas
X      SpriteMaskCanvas /Mapped true put
X    grestore
X  } def
X
X  /HideSprite {
X    SpriteCanvas /Mapped false put
X    SpriteMaskCanvas /Mapped false put
X  } def
X
X  /SpriteShape { % x y => -
X    translate
X    SpriteHotX neg SpriteHotY neg translate
X    0 0 BubbleRadius 0 360 arc
======== END OF cyber.shar.splitab ========