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

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

I am reposting splitaa and splitab to comp.windows.news (but not the
NeWS-makers mailing list) because I screwed up the message id's and
they don't seem to have gotten through. Please excuse any duplicate
postings, like partac. 

The message whose subject is "Cyber Space Deck source code" contains
the word counts and check sums of the split shar files, and instructions for
reassembling. I also posted the text of the paper "The Shape of PSIBER Space:
PostScript Interactive Bug Eradication Routines", and figures 4, 5,
and 7 of the paper. You will probably receive it all in totally random
order. Good luck getting it to work!

	-Don

======== START OF cyber.shar.splitaa ========
: Run this shell script with "sh" not "csh"
PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
export PATH
all=false
if [ x$1 = x-a ]; then
	all=true
fi
echo Extracting README
sed 's/^X//' <<'//go.sysin dd *' >README
XInstructions:
X
XIn a directory containing the files the CyberSpace Deck was distributed
Xwith, just type "cyber".
X
XOr put the .ps files into your NeWS directory (under the directory where
Xyou run NeWS), and "psh cyber.ps" to load them all automatically.
X
XOr load them in the following order:
X
Xecho "(debug.ps) LoadFile pop" | psh
Xpsh textcan.ps
Xpsh piemenu.ps
Xpsh pullout.ps
Xpsh quickwin.ps
Xpsh overlay.ps
Xpsh pointer.ps
Xpsh distill.ps
Xpsh mics.ps
Xpsh cyber.ps
X
XLook at the file "introduction" for instructions.
X
XThe files "arpa.map", and "advent.map" all contain PostScript code
Xthat defined interesting-to-look-at data structures. These are especially
Xfun to visualize as Molecules in CyberSpace. ("etc... molecule")
X
X	-Don
X
//go.sysin dd *
if [ `wc -c < README` != 725 ]; then
	made=false
	echo error transmitting README --
	echo length should be 725, not `wc -c < README`
else
	made=true
fi
if $made; then
	chmod 644 README
	echo -n '	'; ls -ld README
fi
echo Extracting introduction
sed 's/^X//' <<'//go.sysin dd *' >introduction
X========================================================================
X
XThe CyberSpace Deck Manual
X
X  Don Hopkins		     Grasshopper Group		Last update
X  don@brillig.umd.edu	     grass@toad.com		22 July 89
X
X========================================================================
X
XIntroduction
X
XThe CyberSpace deck lets you graphically display and manipulate the many
XPostScript data strutures, programs, and processes living in the virtual
Xmemory space of NeWS.
X
XThe Network extensible Window System (NeWS) is a multitasking object
Xoriented PostScript programming environment.  NeWS programs and data
Xstructures make up the window system kernel, the user interface
Xtoolkit, and even entire applications.
X
XThe CyberSpace deck is one such application, written entirely in
XPostScript, the result of an experiment in using a graphical programming
Xenvironment to construct a interactive visual user interface to itself.
X
XIt displays views of structured data objects in overlapping windows that
Xcan be moved around on the screen, and manipulated with the mouse:  you
Xcan copy and paste data structures from place to place, execute them,
Xedit them, open their substructures up to any depth, adjust the scale to
Xshrink and magnify parts of the display, and pop up menus of other useful
Xcommands.  Deep or complex data structures can be more easily grasped by
Xapplying various views to them.
X
XThere is a window onto a NeWS process, a PostScript interpreter with
Xwhich you can interact (as with an "executive").  PostScript is a stack
Xbased language, so the window has a spike sticking up out of it,
Xrepresenting the process's operand stack.  Objects on the process's stack
Xare displayed in windows with their tabs pinned on the spike.  (Figure
Xxxx) You can feed PostScript expressions to the interpreter by typing
Xthem with the keyboard, or pointing and clicking at them with the mouse,
Xand the stack display will be dynamically updated to show the results.
X
XNot only can you examine and manipulate the objects on the stack, but you
Xcan also manipulate the stack directly with the mouse.  You can drag the
Xobjects up and down the spike to change their order on the stack, and
Xdrag them on and off the spike to push and pop them; you can take objects
Xoff the spike and set them aside to refer to later, and close them into
Xicons so they don't take up as much screen space.
X
XNeWS processes running in the same window server can be debugged using
Xthe existing NeWS debug commands in harmony with the graphical stack
Xand object display.
X
XThe CyberSpace deck can be used as a "hands on" way to learn about
Xprogramming in PostScript and NeWS.  You can try out examples from
Xcookbooks and manuals, and explore and enrich your understanding of
Xthe environment with the help of the interactive data structure
Xdisplay.
X
X========================================================================
X========================================================================
X
XConcepts
X
XThis section describes some concepts that you should be familiar with
Xwhen using the CyberSpace Deck.  It describes the most important types of
XPostScript data structures, and tells you how they look displayed on the
Xscreen.
X
XIt also gives references to sections of other manuals that explain the
Xconcepts in more detail (Delimited by ~tildes~.)
X
X  Referenced Manuals
X
X      ~Blue: Adobe PostScript Language Tutorial and Cookbook~
X      ~Red: Adobe PostScript Language Reference Manual~
X      ~Green: Adobe PostScript Language Design~
X      ~NeWS: NeWS 1.1 Manual~
X
X  Object
X
X      ~Blue 2: Stack and Arithmetic~
X      ~Blue 2.1: The PostScript Stack~
X      ~Red 3.2: Interpreter~
X      ~Green 2.3: The Operand Stack; Objects in the PostScript Language~
X
X      An object is any NeWS data structure that you can push onto the
X      stack or refer to in other objects.  Each object has a type, some
X      attributes, and a value.
X      ~Red 3.4: Data Types and Objects~
X
X      (The word "object" is used here in a more general sense than in
X      "object oriented programming."  The more specific words "class"
X      and "instance" are used instead.)
X      ~NeWS 6: Classes~
X
X      When an object is displayed in a window, its type is displayed
X      in the window tab.  An object's type precedes its value when
X      its displayed inside another object.  Examples:  "array [6]",
X      "integer 100" (Figure xxx)
X
X      Composite objects, such as arrays, strings, and dictionaries, which
X      can be pushed on the stack or referenced by other objects, are
X      represented internally as pointers to their bodies.  So there can be
X      multiple references to any composite object, and its body doesn't
X      get moved around in memory whenever the references are moved or
X      copied.
X      ~Blue 8.1:  PostScript Arrays~
X      ~Red 3.4:  Data Types and Objects; Simple and Composite Objects~
X
X      A reference count is maintained in the body of each composite
X      object.  Once there are no longer any remaining references to an
X      object, its body is automatically garbage collected and its storage
X      is reclaimed.
X      ~NeWS 11.8:  Object Cleanup~
X
X  Executable/Literal
X
X      ~Blue 4.2: Defining Procedures and Variables~
X      ~Red 3.4: Data Types and Objects; Attributes of Objects~
X      ~Green 2.3: The Operand Stack; Objects in the PostScript Language~
X      ~Green 2.7: Procedures~
X
X      Each object has an attribute that makes it either executable or
X      literal.  This affects how the PostScript interpreter deals with it
X      (whether it's used as code or data).  Each reference to an object
X      has its own executable/literal bit, so you can have an executable
X      and a literal reference to the same object at once.
X
X      Executable objects are displayed in an italic font, and literal
X      objects are displayed in a non-italic font.  (Figure xxx)
X
X  String
X
X      ~Blue 5.0: Printing Text; Introduction~
X      ~Red 3.3: Syntax; Strings~
X      ~Red 3.4: Data Types and Objects; String~
X      ~Green 2.6: The Interpreter and the Scanner~
X
X      Strings are delimited by parenthesis:  "string (foobar)" The
X      parenthesis inside the string do not have to be quoted if they
X      balance:  "string (Copyright (C) 1989)" If a string is longer
X      than 80 characters, then only the first 80 are displayed,
X      followed by an elipse:  "string (blablabla...bla)..."
X
X  Name
X
X      ~Blue 4: Procedures and Variables~
X      ~Red 3.3: Syntax; Names"
X      ~Red 3.4: Data Types and Objects; Name~
X      ~Green 2.5: Operators and Name Lookup~
X
X      Names are used as keys in dictionaries, to refer to the values
X      of variables and procedures.
X
X      Executable names are displayed in italics, without a leading
X      slash: "name foo"
X      Literal names are displayed with a slash before them: "name /foo"
X
X  Array
X
X      ~Blue 7: Loops and Conditionals~
X      ~Blue 8: Arrays~
X      ~Red 3.3: Syntax; Arrays, Procedures~
X      ~Red 3.4: Data Types and Objects; Array~
X      ~Red 3.6: Execution: Execution of Specific Types~
X      ~Green 2.7: Procedures~
X
X      PostScript arrays are polymorphic:  Each array element can be an
X      object of any type.  A PostScript procedure is just an executable
X      array of other objects, to be interpreted one after the other.
X
X      Executable arrays (i.e.  procedures) are displayed in italics, with
X      their length enclosed in braces:  "array {37}" Literal arrays are
X      displayed with their length enclosed in square brackets:
X      "array [6]"
X
X      When you open up an array, lines are drawn fanning out to the
X      right, leading from the array to its elements, which are
X      displayed as "index: type value", in a smaller point size.
X
X  Dictionary
X
X      ~Blue 4: Procedures and Variables~
X      ~Red 3.4: Data Types and Objects; Dictionary~
X      ~Green 2.4: The Dictionary Stack~
X      ~Green 2.5: Operators and Name Lookup~
X
X      Dictionaries associate keys with values.  The key (an index into a
X      dictionary) can be an object of any type (except null), but is
X      usually a name.  The value can be anything at all.  Dictionaries
X      are used to hold the values of variables, functions and
X      arguments, as records, lookup tables, classes, instances, and
X      other things -- they're very useful!
X
X      The dictionary stack defines the context of a PostScript process.
X      Whenever the value of a name is needed, it is looked up in the
X      dictionaries on the dictionary stack, in top to bottom order.
X
X      A dictionary is displayed by showing the number of keys it
X      contains, a slash, and the maximum size of the dictionary,
X      enclosed in angled brackets:  "dict <31/200>"
X
X      When you open up a dictionary, lines are drawn fanning out to
X      the right, leading from the dictionary to its elements,
X      which are displayed as "key : type value" in a smaller point
X      size: "/FirstName : string (don)"
X
X  Class
X
X      ~NeWS 6: Classes~
X
X      NeWS uses an object oriented programming package, which
X      uses dictionaries to represent classes and instances.
X
X      When a class dictionary is displayed, its class name is
X      displayed, instead of its actual type "dict":
X      "MessageItem <10/200>"
X
X  Instance
X
X      ~NeWS 6: Classes~
X
X      When an instance dictionary is displayed, its type is displayed
X      as a period followed by its class name:  ".MessageItem <31/200>"
X
X  Magic Dictionary
X
X      ~NeWS 11: NeWS Type Extensions~
X      ~NeWS 11.2: NeWS Type Extensions; Objects as Dictionaries~
X
X      Magic dictionaries are certain types of NeWS objects, such as
X      processes, canvases, and events, that appear to be dictionaries,
X      but are really special data types.  They have a fixed set of keys
X      with special meanings (such as a process's /OperandStack, or a
X      canvas's /TopChild), but otherwise, you can treat them just
X      like regular dictionaries.  Special things may happen when you
X      read or change the values of the keys (for example, setting the
X      /Mapped key of a canvas to false makes it immediately disappear
X      from the screen).
X
X  Selection
X
X      ~Red 3.4: Data Types and Objects~
X      ~NeWS 5: The Extended Input System~
X      ~NeWS 5.4: The Extended Input System;
X		   Selection Overview and Data Structures~
X
X      A selection is a piece of data, such as text from a terminal
X      window, that can be copied and pasted from window to window.
X      Selections are used to move data between separate window system
X      applications.  There are several different ranks of selections
X      that you can make, but the most frequently used one is called the
X      "primary selection".  The CyberSpace deck displays the current
X      primary selection in the field at the top of the scrolling text
X      window.  (figure xxx)  Selections also come in different types,
X      and the following types are currently recognized:
X
X      text
X
X	  A string of ASCII text, selected from something like a
X	  terminal emulator, text canvas, text editor.
X
X      object
X
X	  A single PostScript object, of any type.
X
X      pointer
X
X	  PostScript does not have an explicit notion of a "pointer",
X	  but if we consider the meaning, "a way to reference or
X	  replace an object in memory," the term "pointer" means a
X	  *pair* of PostScript objects:  a container and an index, that
X	  specify the location of another PostScript object.  The
X	  container (usually an array or dictionary) holds the object,
X	  and the index into the container (usually an integer or name)
X	  tells which element of the container the object is.
X
X	  The PostScript operators "get" and "put" take pointers as
X	  arguments.
X	  ~Red 6.3: get, put~
X
X	  The advantage of selecting a pointer to an object, rather
X	  than the object itself, is that whoever uses the selection is
X	  able to tell where the object came from, and/or can replace
X	  the selection with a new value.
X
X      interval
X
X	  A subsequence of an array or string, a contiguous subset of
X	  the original elements, sharing the same storage.
X	  ~Red 6.3: getinterval, putinterval~
X
X  Process
X
X      ~Red 3.5: Stacks~
X      ~NeWS 2.1: NeWS Extensions Overview; The Lightweight Process Mechanism~
X      ~NeWS 11.6: NeWS Type Extensions; Processes as Dictionaries~
X
X  Canvas
X
X      ~NeWS 1.3: Introduction; Canvases~
X      ~NeWS 2.2: NeWS Extensions Overview; Canvases and Shapes~
X      ~NeWS 11.3: NeWS Type Extensions; Canvases as Dictionaries~
X
X  Event
X
X      ~NeWS 1.4: Introduction; User Interaction -- Input~
X      ~NeWS 3: Input~
X      ~NeWS 11.4: NeWS Type Extensions; Events as Dictionaries~
X
X========================================================================
X========================================================================
X
XHow to Get Started
X
XFirst, you have to be running NeWS.  If you don't have a NeWS handy,
Xyou can skip to the next section.
X
XThe CyberSpace deck currently runs under NeWS 1.1, and walks under
XX11/NeWS Beta 2.  (One day it will fly!)
X
XTake a look at the file "README" which should be supplied with the
XCyberSpace deck.  It should contain the latest instructions for loading
Xall the files you need to run it.
X
XIn a directory containing the files the CyberSpace Deck was distributed
Xwith, just type "cyber".
X
XOr put the .ps files into your NeWS directory (under the directory where
Xyou run NeWS), and "psh cyber.ps" to load them all automatically.
X
XOr load them in the following order:
X
Xecho "(debug.ps) LoadFile pop" | psh
Xpsh textcan.ps
Xpsh piemenu.ps
Xpsh pullout.ps
Xpsh quickwin.ps
Xpsh overlay.ps
Xpsh pointer.ps
Xpsh distill.ps
Xpsh mics.ps
Xpsh cyber.ps
X
X========================================================================
X========================================================================
X
XNavigating in CyberSpace
X
XThere are several ways of giving commands to the CyberSpace Deck.  The
Xnumber of "*"'s to the right of the title of a section tell how important
Xsomething is if you are learning to use the CyberSpace deck.  (The more
Xsplats, the more interesting.)
X
X  Clicking with the Mouse						*****
X
X      The most commonly used functions can be performed directly by
X      clicking on things with the mouse buttons.  What a mouse button
X      does depends exactly on what was underneath the cursor when you
X      clicked the button.  For example, the exact word you are on when
X      you bring up a menu is often what the menu will affect.  (This
X      differs from most applications where all that matters is what
X      window you are in.)
X
X  Selecting from Menus							****
X
X      There are a lot of commands available via pop-up menus, that you
X      can get by clicking the "Menu" button (usually the right button).
X      The menu that pops up applies to whatever was underneath the
X      cursor when you first pressed down on the menu button.
X
X  Typing PostScript Expressions						***
X
X      You can type into the scrolling text window (or anywhere else in
X      the CyberSpace Deck window).  What you type is interpreted as a
X      PostScript expression, and you can interact with the PostScript
X      interpreter "executive", as you normally can with an "psh" (or
X      "tip" to a laser printer).
X
X  Pressing Function Keys and Control Characters				**
X
X      Certain function keys and control characters invoke functions
X      immediately when you type them.
X
X  There are several different regions on the screen to interact with...
X
X  The Scrolling Text Window						*****
X
X      The scrolling text window presents a view of a NeWS process.
X      There is a spike sticking out of the top of the window which
X      represents the process's stack.  Text that the process prints
X      to its standard output is put into the text window, and text
X      that you type anywhere in the CyberSpace Deck window is fed
X      into the standard input of the process.
X
X      At the top of the text window is a banner displaying the current
X      primary selection.  Text that you select from a text window,
X      terminal emulator, or other applications goes into the primary
X      selection, along with the objects you select from the deck.
X
X      Text Window Tab							**
X
X	  You can move the text window around by pressing the Point
X	  button (left) down over the tab sticking out of the edge,
X	  dragging it to where you want, and releasing.
X
X	  Clicking the Menu button in the text window tab pops up a pie
X	  menu of commands affecting the process and text window, as well
X	  as a few commands for internal debugging and introspection.
X
X      Text Display							****
X
X	  You can type commands into the text window, to be interpreted
X	  by NeWS.  You can edit the text as you type it in, using the
X	  Delete or Backspace key to erase characters, and Control-X or
X	  Control-U to erase the whole line.  There are a lot of other
X	  functions bound to control characters and function keys, which
X	  you can get a list of by pressing Help, Alternate, or Meta-?.
X	  (Todo:  define a function called "help" in the initial
X	  userdict.)  (To type in a "Meta" character on a Sun keyboard,
X	  hold down the "Left" key.)  One of the most useful keyboard
X	  commands is Meta-Esc (or L9), which displays all the keys on
X	  the dictionary stack that match the partially typed name in the
X	  text window.
X
X	  The scroll bar on the left edge of the text window can be
X	  used to scroll through the lines of text that have been typed
X	  out in the window.  (You'll need to use it to look at the
X	  list of key bindings.)
X
X	  Clicking and dragging the Point and Adjust buttons (left
X	  and middle) over the characters in the text window selects
X	  the text as the primary selection.
X
X	  Clicking the Menu button (right) inside of the text window
X	  pops up a menu of commands that operate on the Primary
X	  selection.
X
X  The Background Menu							****
X
X      If you click the Menu button (right) on the white background of
X      the CyberSpace Deck window, the background menu will pop up.
X      This is a menu of functions that push interesting things onto the
X      stack for you to look at and play with.
X
X      Pallets...							***
X
X	  A pallet is a dictionary or array of useful functions, that
X	  you can open up and execute with the mouse (below).
X	  Selecting the name of a pallet from the "Pallets..."  submenu
X	  pushes a pallet of related functions onto the stack.  You can
X	  open up a pallet and make its click action click-exec, from
X	  the tab menu.  (todo:  make automatic) The "Debug" pallet is
X	  a handy interface to the NeWS debugger (debug.ps).
X
X      Processes								***
X
X	  This pushes an array of arrays of NeWS processes onto the
X	  stack.  Each subarray contains all the processes in one
X	  process group.  (This only works in X11/NeWS.)
X
X      Framebuffer							***
X
X	  This pushes the framebuffer, the root of the canvas hierarchy,
X	  onto the stack.  You can open up a canvas editor on the
X	  framebuffer to see an array of its children (from the
X	  structure "type...canvas editor" submenu) and open up a
X	  scroller editor on the array (also from the structure
X	  "type...scroller editor" submenu).  (todo:  make automatic)
X
X      Windows								****
X
X	  This pushes on the stack a dictionary of every LiteWindow that
X	  has an active event manager listening for /DoIt events.  The
X	  keys of the dictionary are the event managers, and the values
X	  are the windows they are managing.
X
X      Canvases								****
X
X	  This lets you click at a place on the screen, and pushes on
X	  the stack an array of the canvases underneath the cursor where
X	  you clicked.  It draws an "X" shape at the cursor to prompt
X	  you to click somewhere.
X
X      Object								****
X
X	  This pushes the class Object, the root of all other classes,
X	  onto the stack.  You can open up an class editor on class
X	  Object (from the structure "type...class editor" submenu).
X	  (todo:  make automatic) You can open up Object's arrays of
X	  SubClasses and ClassDicts, and open class editors on classes
X	  in them, too.  You can enter the context of the class or
X	  instance (from the structure "type...enter" submenu), and open
X	  up scroller editors (from the "type...scroller editor"
X	  submenu) on the class editor's arrays of InstanceVars,
X	  ClassVars, and Methods, and open up name editors on the names
X	  contained therein.  (todo:  make it open up collections of
X	  actual pointers to the objects, so you don't need to enter the
X	  object's context, and you can open them up and edit them.)
X
X  The Data Structure Views						*****
X
X      Views of PostScript data structures are displayed in windows with
X      tabs sticking out of them.  The tabs display the type of data
X      structure being viewed in the window.
X
X      View Window Tab							*****
X
X	Moving the View Window						*****
X
X	  You can press the Point button (left) down on a tab, and drag
X	  the window around on the screen.  When you release the button,
X	  the window will stay where it is (usually).  If you place it
X	  so the tab overlaps the pin sticking out of the top of the
X	  scrolling text window, it will be pushed onto the stack.  You
X	  can move objects around on the stack by dragging them up and
X	  down the spike by the tabs.
X
X	Iconifying the View Window					**
X
X	  If you press the middle button over a structure window tab, it
X	  will iconify the window, so it displays only the first level
X	  of the data structure, with a rounded line drawn around the
X	  inside border.  This isn't particularly useful for windows
X	  that are only displaying one level of data structure in the
X	  first place, but it sure is handy for big deep ones.
X
X	View Window Tab Menu						*****
X
X	    Pressing the menu button over the tab of a structure window
X	    pops up a menu of operations on that whole window.
X
X	    Layout							*
X
X		Recompute the layout of the structure.  Updates the
X		display if the structure has changed.
X
X	    Paint							**
X
X		Redraw the structure.
X
X	    Zap								*****
X
X		Destroy the view of the data structure.  If the window
X		is on the stack, then the object is popped.  Zapping a
X		view window does not destroy the displayed data
X		structure itself, unless there are no other references
X		to it, in which case it gets garbage collected
X		automatically.
X
X	    Print							*
X
X		Write out a PostScript program to print out the
X		structure display. This is presently broken, but at
X		least it doesn't seem to crash.
X
X	    Tab...							**
X
X		Submenu to move the tab to different places around the
X		window.  Ignore the names, just select the direction in
X		which you want the tab moved.
X
X	    View...							*****
X
X	        Menu of functions that affect the view of the
X		structure in the window. The attributes you set
X		with this menu can be overridden locally in the
X		individual pieces of structure, with the structure
X		view menu.
X
X		point size						*****
X
X		    Change the point size at which the top level piece
X		    of structure is displayed.  Pull out further to get
X		    a bigger point size.  The size you have selected is
X		    displayed in the menu center.
X
X		shrink							***
X
X		    Change the factor by which the point size
X		    diminishes with depth.  Pull out further to get a
X		    bigger shrink factor.  (If it's more than one then
X		    it's a grow factor!)  The factor you have selected
X		    is displayed in the menu center.
X
X	        open							***
X
X		    Open the structure to a certain depth.  Pull out
X		    further to open it deeper.  The depth to which
X		    the structure will be opened is displayed in the
X		    menu center.  Be careful about opening big
X		    structures deeper than one or two levels at once,
X		    unless you have a lot of time to wait!
X
X	        click proc...						*
X
X		    Sets the function to call when you click the Adjust
X		    (middle) button on a piece of structure in that
X		    window.  These are described later, but the most
X		    useful one for pallets of functions is "click-exec".
X		    An object whose click action is click-exec will be
X		    executed when you click the Adjust button on it.
X
X      Structure View							*****
X
X	  A mouse sensative structural view of PostScript data is
X	  displayed inside the view window.  You can use the mouse to
X	  point at a piece of structure in the display, inspect and
X	  manipulate it.  No matter how small something is displayed
X	  (even in unreadable 1-point text), it is still mouse sensative!
X	  (It won't shrink any smaller than a pixel, so you can always
X	  point to it.)
X
X	  Selecting Data Structures					*****
X
X	      Clicking once on an object with the Point button (left)
X	      will select the object.  This actually selects a "pointer"
X	      to the object (see above), and you will see it as the
X	      current primary selection, displayed in the line labeled
X	      "Selected:"  at the top of the scrolling text window.
X
X	      You can hold the Point button down and drag the cursor up
X	      and down to select other pieces of structure in the same
X	      container.  The currently selected structure will be
X	      displayed in the banner at the top of the scrolling text
X	      window.
X
X		    If you hold the shift key down while making a data
X		    structure selection, the results you get will depend
X		    on the type of the container from which you're
X		    selecting.  If it's a dictionary, you can select one
X		    of its keys.  If it's an array, you can drag the
X		    cursor up and down to select an array subinterval.
X
X	  Executing Data Structures					****
X
X	      Double clicking the Point button on an object selects it,
X	      makes it executable, and executes it.  This is useful for
X	      calling functions that are displayed on the screen, and
X	      for using strings of text, such as previously typed
X	      commands selected from a text window, as command buttons.
X
X	  Doing Other Stuff to Data Structures				*****
X
X	      Clicking the Adjust button (middle) on a structure calls
X	      the structure's click action, or the default click action
X	      of the structure window if the particular piece of
X	      substructure does not have its own.  There are several
X	      different click actions, such as click-exec, click-push,
X	      and click-select, but click-transfer is the default.
X
X	      The Default Click Action					*****
X
X		  Here are the three ways to use "click-transfer":
X
X		  Open/Close Structure					*****
X
X		      Press and release the Adjust (middle) button over
X		      a composite object like a dictionary, an array,
X		      canvas, or process.  The structure will open up
X		      one level deep (or close if it was already
X		      opened).
X
X		  Transfer to Background				*****
X
X		      Press the Adjust button over an object, and
X		      holding it down, drag the object out over the
X		      background.  When you release the button, a new
X		      view window will appear on the background.  It
X		      will contain a copy of the object you just dragged
X		      out.
X
X		  Transfer to Structure					*****
X
X		      If you drag an object over to another structure
X		      window (or to the same one, but over a different
X		      piece of substructure), and release the button,
X		      the object will be pasted into the structure
X		      underneath the cursor when you released the
X		      button.  Now you are actually editing PostScript
X		      data structures!  Be careful!  You can severly
X		      hose your NeWS server if you start pasting things
X		      into system data structures or functions.  Make a
X		      few of your own dictionaries and arrays to play
X		      around with!
X
X	  Structure Menu						*****
X
X	      If you click the Menu button (right) over a piece of
X	      structure, you will pop up a structure menu with lots of
X	      functions which operate on the object under the cursor at
X	      the time you pressed the Menu button.
X
X	      push							*****
X
X		  Push the object onto the stack.
X
X	      exec							*****
X
X		  Make the object executable, and execute it.
X
X	      paste							*****
X
X		  Paste the primary selection into the place of the
X		  object under the cursor.  This actually edits
X		  PostScript data structures!  See the above warning in
X		  the description of click-transfer!
X
X              open...							****
X
X		  Submenu of functions to open up an object in different
X		  ways.  Pull out further to open it deeper.  The depth
X		  to which the structure will be opened is displayed in
X		  the menu center.
X
X	      change...							***
X
X		  Submenu of functions that perform type conversions on
X		  the object (or at least they try).
X
X	      view...							****
X
X		  Submenu of functions that affect the local view of
X		  the piece of structure.  Similar to the view submenu
X		  on the structure window tab, except that these
X		  functions apply just to the piece of structure under
X		  the cursor and its children, not all pieces of
X		  structure in the window.
X
X	      etc...							**
X
X		  Submenu of random but useful functions that wouldn't
X		  fit anywhere else. The "Molecule" function pops up
X		  a pseudo-scientific visualizer view of the
X		  PostScript data structure under the cursor.
X
X	      type...							*****
X
X		  Pops up a type-specific submenu of functions that
X		  apply to the object under the cursor at the time you
X		  popped up the structure menu.  Which menu you get
X		  depends on the type of the object.
X
X========================================================================
X
X========================================================================
X
XType Specific Functions
X
X========================================================================
X
XEditors
X
X    boolean
X
X    canvas
X
X    class
X
X    definitions
X
X    digit
X
X    element
X
X    filter
X
X    scroller
X
X    shift
X
X    step
X
X    user
X
X========================================================================
X
XPallets
X
X    Window
X
X    Debug
X
X========================================================================
X
XDebugging
X
X    break-cont
X
X    break-copy&cont
X
X    break-enter
X
X    break-exit
X
X    break-kill
X
X    break-list
X
X    clear
X
X    enter-it
X
X    exit
X
X    fix-typo
X
X    push-dictstack
X
X    push-execstack
X
X    push-process
X
X    show-dictstack
X
X    show-execstack
X
X========================================================================
//go.sysin dd *
if [ `wc -c < introduction` != 30173 ]; then
	made=false
	echo error transmitting introduction --
	echo length should be 30173, not `wc -c < introduction`
else
	made=true
fi
if $made; then
	chmod 644 introduction
	echo -n '	'; ls -ld introduction
fi
echo Extracting piemenu.ps
sed 's/^X//' <<'//go.sysin dd *' >piemenu.ps
X%!
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X%  @(#)piemenu.ps
X%
X%  Pie menu class implementation.
X%  Copyright (C) 1987.
X%  By Don Hopkins.
X%  All rights reserved.
X%
X%    Simple Simon popped a Pie Men-
X%	u upon the screen;
X%    With directional selection,
X%	all is peachy keen!
X%
X%  Pie Menus are 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% May 28 1987	Don Hopkins
X%   First cut, based on LitePullRightMenu.
X%
X% May 30 1987	Don Hopkins
X%   Uses "Thing"s from liteitem.ps for key labels. A thing can be a
X%     string, or a keyword. The string is shown in MenuFont. The
X%     keyword can be either the name of an icon in icondict, or bound
X%     on the dict stack to an executable function. The function takes
X%     a boolean as input; if true, it draws itsself; if false, it
X%     returns its width and height.
X%     NOTE: in NeWS 1.1, a Thing is either: a string, a keyword (icon
X%	    name only), an executable array (taking /draw or /size as
X%           input), or an Object dict (sent a /draw and /size messages).
X%	    See the colornames demo!
X%   Better label positioning scheme: top or bottom justify labels at
X%     at the very bottom or top of the menu, and left or right justify
X%     labels on the right or left sides of the menu. The points
X%     relative to which the labels are justified are positioned at
X%     evenly spaced angles in a circle around the menu center. The
X%     instance variable PieInitialAngle is the angle of the first
X%     point. LabelRadius is the distance from the menu center to each
X%     point, calculated as:
X%       LabelMinRadius + LabelRadiusPerKey * <the number of menu keys>
X%     NOTE: LabelRadiusPerKey is obsolete now. LabelRadius is automatically
X%           pushed out until no labels overlap.
X%   If the menu can't be centered on the location of the button
X%     event that invoked it, then warp the cursor to the menu center
X%     plus how much it has moved since the button down event, so that
X%     pop up menus near the screen edge and static menus work
X%     correctly. But ARRRGH FOO: setcursorlocation is broken!!! It
X%     moves the cursor, but next time you move the mouse, the cursor
X%     pops back to where it used to be! The Sun X server used to have
X%     the same problem with XWarpMouse. Makes you wonder. Well,
X%     anyway, I commented it out, because it's more confusing with
X%     setcursorlocation broken than it is not warping at all.
X%     NOTE: It's fixed now, so it works right!
X%
X% July 13 1987	Don Hopkins
X%   Fixed up handling of retained canvases. Changed SliceLines to
X%     SliceWedges, and made it draw wedges inside of LabelRadius.
X%     Put in MoveMenu, which moves the menu, making sure that it's
X%     completely on the screen, and the mouse is in the menu center.
X%     (The latter part should be uncommented when setcursorlocation
X%     is fixed.) Changed slice highlighting.
X%   Implemented an oops function. Pressing the adjust button moves
X%     the top menu so the cursor's back in its center. (Well,
X%     setcursorlocation is still broken ...) If the mouse is already
X%     in the menu center, then the menu is popped down and the
X%     one below it is moved so its center is at the cursor.
X%     NOTE: Oops works much better now that setcursorlocation is fixed!
X%           On AdjustButton Down (Ker), the cursor moves to the menu center.
X%           On AdjustButtonUp (Chunk), if the cursor is still in the menu
X%           center, the menu is popped down, leaving you in the previous
X%	    menu (if any), at the location you invoked this menu from.
X%
X% July 24 1987  Don Hopkins
X%   Changed to work with NeWS 1.1 litemenu.ps ... (just in time for SIGGRAPH!)
X%
X% August 20, 1987  Don Hopkins
X%   Uncommented out and fixed the mouse warping code. Added display
X%   interruption, so that if the events that would make the menu
X%   selection are already in the event queue, then the menu is not
X%   displayed. I'm not sure if the way I'm doing it is the best way,
X%   but it seems to work. I'm still not sure that the way mouse warping
X%   near the screen edge and display interruption are interacting is
X%   really correct. It should not warp the mouse if the events are
X%   already in the queue, so maybe warping should be defered, as well.
X%   There was also a problem with /Damaged events generated when the
X%   canvas is reshaped, being put into the queue before the /MapMenu
X%   event is. This was causing the menu to be painted before the
X%   defered mapping took place, which is not the way I think it should
X%   work. So I kludged around it. There's got to be a safer way to
X%   make it work right.
X%   NOTE: This kludge has been flushed in favor of drawing the menu
X%         before it's mapped.
X%	  A delay has been added to the map event, to facilitate mouse-ahead
X%	  display suppression. If you click down and up, without moving out
X%	  of the menu center, you will get the menu as soon you let up, but
X%	  if you click down and move, without letting up, there will be a
X%	  delay before it is mapped, during which time if you let up in an
X%	  active slice region, the mapping of the menu will be suppressed
X%	  (unless there is a submenu), and the selection you have chosen
X%         acted upon immediatly. The submenu delay is shorter than the delay
X%         of a menu with no parent, so that when you mouse-ahead quickly
X%         into a submenu, you will see the submenu mapped first. (Because
X%	  the parent menu is less important than the active submenu, now
X%         that you've already made the selection.) This may sound quite
X%         bizarre, but it seems to work pretty nicely for me.
X%
X% March 29, 1988  Don Hopkins
X%    Lots of changes have been made, too many to go into excruciating
X%    detail, but I've put notes in the above comments to bring them
X%    somewhat up to date. Please destroy any evil old copies of
X%    piemenu.ps and replace them with this!!!
X%
X% August 28, 1988  Don Hopkins
X%    Fixed "go!" so the framebuffer's event manager would not end up
X%    with the currentcanvas of the process from which it was invoked.
X%    (This was causing damage on the framebuffer not to be repainted
X%    if piemenu.ps was run from a menu.)
X%    Added the DontSetDefaultMenu flag.
X%
X% February 17 1989  Don Hopkins
X%    Changed MapMenuEvent handler so that mapping is defered until
X%    the mouse stops moving around.
X%
X% March 7 1989  Don Hopkins
X%    Finally figure out some sort of light-weight feedback to use with
X%    mouse-ahead display suppression, short of mapping the menu.  When
X%    popping down a menu whose display was supressed, draw a circle
X%    where the menu would have been, with the selected slice cut out.
X%    (Direct Pac-Manipulation feedback.)
X%
X% November 20 1989  Don Hopkins
X%    Fixed it to work with X11/NeWS Version 1.0 (FCS).
X%    Don't set DefaultMenu if xnews.
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X% Things to do:
X%
X% Teach it to use items as menu keys. Create PieItems like buttons,
X%   cycles, sliders and pull-out menus based on the distance,
X%   etc... (Use Things that are Objects!)
X%
X% Make each slice a canvas, and map just the choosen slices. Leave
X%    a trail of wedges to the current active submenu.
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
Xsystemdict begin
X
Xsystemdict /XNeWS? known not {
X  /XNeWS? false def
X} if
X
Xsystemdict /Item known not {
X  (NeWS/liteitem.ps) LoadFile not {
X    (Can't load liteitem.ps!\n) print
X  } if
X} if
X
Xsystemdict /LiteMenu known not {
X  (NeWS/litemenu.ps) LoadFile not {
X    (Can't load litemenu.ps!\n) print
X  } if
X} if
X
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X% Utilities
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
X% XNeWS is missing these functions so make dummies if they're not defined.
X% XXX: Can all the calls to these be eliminted in NeWS 1.1?
X
X/overlaydraw nullproc ?def
X/overlayerase nullproc ?def
X
X% Replace the go! function with one that starts a root event manager
X% that listens for (and ignores) menu button up events. This is so they
X% don't get dropped on the floor before a pie menu can express interest
X% in them. (Crucial for effective mouse-ahead!)
X/go! {
X    verbose? { (Starting root eventmgr\n) print } if
X    /rooteventmgr where { pop
X      rooteventmgr type /processtype eq {
X	rooteventmgr killprocess
X      } if
X    } if
X    {
X    countdictstack 1 sub {end} repeat
X    framebuffer setcanvas
X    /rooteventmgr [
X	/rootmenu where { pop
X	    MenuButton
X	    { {newprocessgroup /showat rootmenu send} fork pop }
X	    /DownTransition framebuffer eventmgrinterest
X	    MenuButton
X	    { CurrentEvent redistributeevent } null null eventmgrinterest
X	    dup /Priority -5 put
X	    AdjustButton
X	    { CurrentEvent redistributeevent } null null eventmgrinterest
X	    dup /Priority -5 put
X	} if
X
X	/Damaged
X	{newprocessgroup damagepath clipcanvas PaintRoot newpath clipcanvas}
X	null framebuffer eventmgrinterest
X    ] forkeventmgr def
X    } fork pop
X} def
X
X
X/rooteventmgr where { pop
X  XNeWS? not
X  systemdict /DontSetDefaultMenu known not  and
X  rooteventmgr type /processtype eq  and {
X    go!
X  } if
X} if
X
X% Coerce an angle to be >=0 and <360.
X% Note: mod returns integers, so's no good.
X/NormalAngle { % angle => angle
X  dup 0 lt {
X    dup 360 sub 360 idiv 360 mul sub
X  } if
X  dup 360 ge {
X    dup 360 idiv 360 mul sub
X  } if
X} def
X
X% From demomenu.ps
X
X% Fake method to send to a menu that returns a copy of the menu in the
X% new menu style. Recursivly changes all sub-menus. One thing to look
X% out for is that it does not change variables bound to the sub-menus
X% that were changed, so setting /rootmenu to the result of sending
X% /flipstyle to rootmenu will give you a new root menu, with a new
X% terminal sub-menu, but /terminalmenu will still be bound to the old
X% one, so sending messages to terminalmenu will not change the
X% terminal menu you get under the new rootmenu. But sending /flipstyle
X% to terminalwindow would not update the terminal menu under rootmenu.
X% So get your changes in before you flip styles! Or use /searchkey to
X% find the new menu, and re-def it in systemdict.
X
X/flipstyle { % - => newmenu
X    0 1 MenuActions length 1 sub {
X	dup getmenuaction % fixed to use getmenuaction!
X	dup type /dicttype eq {
X	    /flipstyle exch send	% i menu'
X	    MenuActions 3 1 roll put	% -
X	} {pop pop} ifelse
X    } for
X    MenuKeys MenuActions /new DefaultMenu send
X} def
X
X
X% Override flipdefaultmenustyle, a function invoked from the user
X% interface menu.
X
X/flipdefaultmenustyle { % - => - (Flips default menu style)
X  /DefaultMenu
X    DefaultMenu SunViewMenu eq {PieMenu} {SunViewMenu} ifelse
X  store
X} def
X
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X% SimplePieMenu class
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
X/SimplePieMenu LiteMenu
X
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X% Instance variables
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
Xdictbegin
X% The slice currently painted.
X    /PaintedValue	null def
X% Inner radius around which labels are positioned. Based  LabelMinRadius,
X% LabelRadiusPerKey, and the length of MenuKeys.
X    /LabelRadius	null def
X% Pie menu outer radius. Based on LabelRadius and the bounding boxes of
X% the Key Things.
X    /PieRadius		null def
X% The number of degrees a slice takes up. Based on length of MenuKeys.
X    /PieSliceWidth	null def
X% The current direction in degrees from the menu center to the cursor.
X    /PieDirection	null def
X% The current distance from the menu center to the cursor.
X    /PieDistance	null def
X% Angle used in loops.
X    /ThisAngle		null def
X% Amount to move the menu so that it fits entirely on the screen.
X    /DeltaX		null def
X    /DeltaY		null def
X% Flag to remember if we've gotten a menu button down event before.
X    /GotDown		false def
X% Interruptable display event
X    /MapMenuEvent       null def
X    /CurX		0 def
X    /CurY		0 def
Xdictend
X
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X% Class variables
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
Xclassbegin
X% Highlight: true strokes, false fills.
X    /StrokeSelection	false def
X% Width of border just inside PieRadius perimiter.
X    /Border		3 def
X% Gap between outermost label edge and border.
X    /Gap		9 def
X% Radius of numb hole in menu center that makes no menu selection.
X    /NumbRadius		14 def
X% Fudge factors for menu positioning.
X    /MouseXDelta	0 def
X    /MouseYDelta	-3 def
X% Draw lines delimiting slices.
X    /SliceWedges	true def
X% Draw arrows in the directions of slices.
X    /SliceArrows	false def
X% Drill a hole through the menu center, as big as NumbRadius.
X    /NumbHole		false def
X% Save the bits so pop-up is fast.
X%    /RetainCanvas?	true def
X    /RetainCanvas?	false def
X% Nice menu font...
X    /MenuFont		/Helvetica-Bold findfont 12 scalefont def
X% Draw arrow pointing to current selection?
X    /HiLiteWithArrow?	true def
X% Menu line attributes
X    /MenuLineWidth 0 def
X    /MenuLineCap 1 def
X    /MenuArrowWidth 1 def
X    /MenuArrowCap 1 def
X% Minimum radius for label positioning.
X    /LabelMinRadius	25 def
X% Radius to step by when sizing menu
X    /LabelRadiusStep	5 def
X% Extra radius to add when sizing menu
X    /LabelRadiusExtra	10 def
X% Direction in which the keys are laid out around the circle.
X    /Clockwise		true def
X% The angle at which the first key is placed.
X    /PieInitialAngle	90 def % up
X% Don't ask.
X    /SplatFactor	0 def
X% Delays to use before mapping, if a button up has not happened yet.
X    /MapLongDelay	.6 60 div def % root menu popup delay
X    /MapShortDelay	.25 60 div def % submenu popup delay
X    /NoMapDist		10 def
X% Direct Pac-Manupulation Feedback
X    /Wocka		true def
X    /WockaTime		.05 60 div def
X
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X% Class methods
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
X% Calculate and set the menu
X% LabelRadius, PieRadius, MenuWidth, and MenuHeight. Shape the canvas
X% and set the cursor.
X
X    /layout {
X      gsave MenuFont setfont initmatrix
X
X	/PieSliceWidth 360 MenuKeys length 1 max div store
X
X	% Get the size of all the keys, and point them in the right direction
X	/ThisAngle PieInitialAngle store
X	MenuItems {
X	  begin
X	    w null eq
X	      {/Key load ThingSize /h exch def /w exch def} if
X	    /ang ThisAngle def
X	    /dx ang cos def
X	    /dy ang sin def
X	    dx abs .05 lt { %  top or bottom
X	      /xoffset w -.5 mul def
X	      /yoffset ang 180 gt {h neg} {0} ifelse def
X	    } { %  left or right
X	      /xoffset ang 90 gt ang 270 lt and {w neg} {0} ifelse def
X	      /yoffset h -.5 mul def
X	    } ifelse
X	    /ThisAngle ThisAngle PieSliceWidth
X	      Clockwise {sub} {add} ifelse
X	      NormalAngle store
X	  end
X	} forall
X
X	% Push the keys out so none of them overlap
X	/LabelRadius LabelMinRadius def
X	MenuItems length 1 gt {
X	  0 1 MenuItems length 1 sub {
X	    /i exch def
X	    /nexti i 1 add MenuItems length mod def
X	    {
X	      i calcrect
X	      nexti calcrect
X	      rectsoverlap not {exit} if
X	      /LabelRadius LabelRadius LabelRadiusStep add def
X	    } loop
X	  } for
X	} if
X	/LabelRadius LabelRadius LabelRadiusExtra add def
X
X	/PieRadius LabelRadius dup mul def
X        MenuItems {
X	  begin
X	    /x dx LabelRadius cvr mul def % XXX: cvr is for NeWS math bug
X	    /y dy LabelRadius cvr mul def
X
X	    /X x xoffset add def
X	    /Y y yoffset add def
X
X	    dx abs .05 lt { %  top or bottom
X	      x abs w 2 div add dup mul y abs h add dup mul add
X	    } { %  left or right
X	      x abs w add dup mul y abs h 2 div add dup mul add
X	    } ifelse
X	    PieRadius max /PieRadius exch store
X	  end
X	} forall
X	/PieRadius PieRadius sqrt Gap add Border add round store
X
X        /MenuWidth
X	  PieRadius dup add store
X        /MenuHeight
X	  MenuWidth store
X
X      grestore
X    } def
X
X    /calcrect { % item_number => x y w h
X      MenuItems exch get begin
X        LabelRadius dx mul xoffset add
X	LabelRadius dy mul yoffset add
X	w h
X      end
X    } def
X
X    /reshape {
X      MenuGSave
X	framebuffer setcanvas
X	newpath
X	PieRadius dup dup 0 360 arc
X	closepath
X	NumbHole {
X	  PieRadius dup NumbRadius 1 sub 360 0 arcn closepath } if
X	SplatFactor { 6 { PieRadius dup add random mul } repeat
X	              curveto } repeat
X	MenuCanvas eoreshapecanvas
X	/beye /beye_m MenuCanvas setstandardcursor
X	% So retained canvases don't have their old image upon popup:
X	RetainCanvas? {
X	    MenuCanvas setcanvas
X            MenuFillColor fillcanvas
X	} if
X      grestore
X    } def
X
X% Make sure nothing's highlighted if there's a retained canvas.
X% Layout the menu, make the canvas, and reshape it, as needed.  Try to
X% center the menu on (XLocation, YLocation) (the location of the event
X% or the (X, Y) arguments), but if needed, move it so that it's
X% completely on the screen, remembering the distance moved in (DeltaX,
X% DeltaY), for repositioning the mouse later. Set up the canvas. Send
X% out a MapMenuEvent with a delay, so that we can supress the mapping
X% if we receive the events that complete the selection right away.
X% (This is mouse-ahead display suppression.) (Submenus have a shorter
X% delay than parentless menus, because if you mouse quickly into a
X% submenu, then wait, you're more immediatly interested in seeing the
X% submenu than the parent.) Finally, reset the menu value, and
X% activate the menu event manager.
X
X    /showat { % event => -
X
X	PaintedValue null ne MenuCanvas null ne and MenuWidth null ne and {
X	    MenuGSave
X	        PaintedValue PaintSlice
X	    grestore
X	} if
X	/PaintedValue null store
X
X	MenuEventMgr null ne {MenuEventMgr waitprocess pop} if
X
X	MenuWidth null eq {
X	  /layout self send
X	  MenuCanvas null ne {/reshape self send} if
X	} if
X
X	MenuCanvas null eq {
X	  /MenuCanvas ParentCanvas newcanvas def
X	  MenuCanvas /Retained RetainCanvas? put
X	  MenuCanvas /SaveBehind ColorDisplay? put
X%	  MenuCanvas /SaveBehind true put
X	  /reshape self send
X	} if
X
X	MapMenuEvent null eq {
X	  /MapMenuEvent createevent def
X	  MapMenuEvent begin
X	    /Name /MapMenu def
X	  end % MapMenuEvent
X	} if
X	MapMenuEvent /Canvas MenuCanvas put
X
X	gsave
X	framebuffer setcanvas
X	dup type /eventtype eq {
X	    begin XLocation YLocation end
X	} if
X	PieRadius sub MouseYDelta add /MenuY exch def
X	PieRadius sub MouseXDelta add /MenuX exch def
X
X	currentcursorlocation /CurY exch def /CurX exch def
X
X	clippath pathbbox /DeltaY exch def /DeltaX exch def pop pop
X
X	/DeltaY
X	  MenuY MenuHeight add
X	  dup DeltaY ge {
X	    DeltaY exch sub
X	  } {
X	    dup MenuHeight lt {
X	      MenuHeight exch sub
X	    } { pop 0 } ifelse
X	  } ifelse
X	def
X
X	/DeltaX
X	  MenuX MenuWidth add
X	  dup DeltaX ge {
X	    DeltaX exch sub
X	  } {
X	    dup MenuWidth lt {
X	      MenuWidth exch sub
X	    } { pop 0 } ifelse
X	  } ifelse
X	def
X
X	/MenuX MenuX DeltaX add store
X	/MenuY MenuY DeltaY add store
X
X%	MenuCanvas savebehindcanvas
X        MenuCanvas setcanvas MenuX MenuY movecanvas
X        MenuCanvas canvastotop
X
X	grestore
X
X% Defer the mapping till events already in the input queue
X% have been processed.
X
X        MapMenuEvent recallevent
X
X	    % So active submenu pops up before already choosen parent!
X	MapMenuEvent /TimeStamp currenttime MapShortDelay add put
X
X        MapMenuEvent sendevent
X
X	/MenuValue null def
X	/GotDown false def
X
X	/activate self send
X    } def
X
X    /paint {
X      MenuGSave
X        PaintMenuFrame
X	PaintMenuItems
X      grestore
X    } def
X
X    /PaintMenuFrame {
X      MenuGSave
X
X        MenuFillColor fillcanvas
X
X	PieRadius dup translate
X
X	newpath
X	0 0 PieRadius 0 360 arc closepath
X	0 0 PieRadius Border sub 0 360 arc closepath
X%	0 0 NumbRadius 0 360 arc closepath
X	MenuBorderColor setcolor eofill
X      grestore
X    } def
X
X    /PaintMenuItems {
X      MenuGSave
X	false setprintermatch
X        PieRadius dup translate
X
X        MenuItems {					% item
X	begin
X	  MenuTextColor setcolor
X	  /Key load X Y ShowThing
X
X% There seems to be a NeWS line clipping bug with lines with one
X% endpoint the right of the hole in the center of the menu ...
X
X	  2 setlinequality % Solves SOME of the line glitches ...
X          MenuLineWidth setlinewidth
X	  MenuLineCap setlinecap
X
X	  SliceWedges {
X	    gsave
X	      newpath
X	      ang PieSliceWidth 2 div sub rotate
X	      NumbRadius 0 moveto
X	      LabelRadius Gap sub 0 lineto
X              MenuBorderColor setcolor
X	      stroke
X 	    grestore
X	  } if
X
X	  SliceArrows {
X	    gsave
X	      MenuArrowWidth setlinewidth
X	      MenuArrowCap setlinecap
X	      newpath
X	      ang rotate
X	      NumbRadius 0 moveto
X	      LabelRadius .5 mul 0 lineto
X	      currentpoint
X	      LabelRadius .4 mul LabelRadius .04 mul lineto
X	      moveto
X	      LabelRadius .4 mul LabelRadius -.04 mul lineto
X              MenuBorderColor setcolor
X	      stroke
X 	    grestore
X	  } if
X        end
X        } forall
X      grestore
X    } def
X
X% Handle drag events. If there's not a child menu up, then track the
X% mouse movement, updating the menu value according the the event
X% location; if it has changed, then update the highlighting.
X
X    /DragProc {
X	ChildMenu null eq {
X          MenuGSave
X	    PieRadius dup translate
X	    CurrentEvent begin
X	      XLocation DeltaX add
X	      YLocation DeltaY add
X	    end
X	    SetMenuValue
X
X	    MenuValue PaintedValue ne {
X	        PaintMenuValue
X            } if
X          grestore
X	} if
X    } def
X
X% Handle enter canvas events. Just call DragProc to keep the menu
X% value updated.
X
X    /EnterProc {
X	DragProc
X    } def
X
X% Handle exit canvas events. Same as above. Here we keep tracking even
X% when you're off the menu edge (due to expressing interest in events
X% on the null canvas). But if it really turns you on, going off the
X% edge could mean no selection (like when you're within the numb
X% radius - look at SetMenuValue), or select the slice, or pop up a
X% submenu, or drag the menu around, or give more info about the slice,
X% or whatever.
X
X    /ExitProc {
X        DragProc
X    } def
X
X    % Pop back to the center of the menu.
X    /KerProc {
X      MenuGSave
X        DragProc
X        framebuffer setcanvas
X        MenuX PieRadius add MouseXDelta sub
X        MenuY PieRadius add MouseYDelta sub
X        setcursorlocation
X      grestore
X    } def
X
X    % Pop back to the previous menu, if we're in this menu's center.
X    /ChunkProc {
X      MenuGSave
X        DragProc
X        MenuValue null eq {
X	    popdown
X	} if
X      grestore
X    } def
X
X% Map the menu on the screen. This is invoked when we get a /MapMenu
X% event, so that we can interrupt the display of the menu (by
X% recalling the event) if the events that would complete the selection
X% are already in the input queue.
X
X    /MapMenu {
X      gsave
X      DeltaX 0 ne DeltaY 0 ne or {
X        framebuffer setcanvas
X        currentcursorlocation
X        exch DeltaX add
X        exch DeltaY add
X        setcursorlocation
X	/DeltaX 0 def  /DeltaY 0 def
X      } if
X
X%      MenuCanvas /SaveBehind ChildMenu null eq put
X      MenuCanvas /Mapped true put
X      grestore
X    } def
X
X    /MaybeMapMenu {
X      gsave
X	framebuffer setcanvas
X	CurX CurY
X	currentcursorlocation /CurY exch def /CurX exch def
X	CurY sub dup mul exch CurX sub dup mul add
X	NoMapDist gt {
X	  MapMenuEvent /TimeStamp currenttime
X	  ChildMenu null eq MapShortDelay MapLongDelay ifelse add put
X	  MapMenuEvent sendevent
X	} {
X	  MapMenu
X	} ifelse
X      grestore
X    } def
X
X    /popdown {
X
X        % Direct Pac-Manipulation Feedback
X	Wocka  MenuCanvas /Mapped get not and {
X	    MenuValue null ne {
X	      gsave
X		MenuItems MenuValue get begin
X		    fboverlay setcanvas
X		    overlayerase erasepage
X		    0 setgray
X		    MenuX PieRadius add MenuY PieRadius add translate
X		    ang rotate
X		    0 0 moveto
X		    0 0 PieRadius % x y r
X		    PieSliceWidth 2 div dup neg arc
X		    closepath
X		    fill
X		    CurrentEvent /TimeStamp get WockaTime add
X		    { pause
X		      dup currenttime lt { exit } if
X		    } loop pop
X		    overlayerase erasepage
X		end % Item
X	      grestore
X	    } if
X	} if
X
X        MapMenuEvent recallevent
X
X	MenuCanvas null ne {MenuCanvas unmapcanvas} if  % spin needs this??
X
X	RetainCanvas? not {
X	    /MenuCanvas null store
X	    /MenuInterests null store
X%	    /MenuWidth null store
X	} if % framebuffer setcanvas?
X
X	ChildMenu null ne {
X	  /popdown ChildMenu send
X	} if
X
X	ParentMenu null ne {
X	  ParentMenu /ChildMenu null put
X	  /ParentMenu null store
X	} if
X
X	MenuEventMgr null ne {
X	    MenuEventMgr /MenuEventMgr null store killprocess
X	} if
X
X    } def
X
X% Calculate and set the menu value from the cursor x y location.
X% Updates /PieDistance and /PieDirection instance variables.
X
X    /SetMenuValue { % x y => - (Sets /MenuValue)
X        /PieDistance
X	  2 index cvr dup mul 2 index cvr dup mul add sqrt round cvi def
X	PieDistance 0 eq { pop pop 0 } { exch atan } ifelse
X	/PieDirection exch round cvi def
X	/MenuValue
X	  PieDistance NumbRadius le
X% It could be that when the cursor is out past the menu radius,
X% nothing is selected. But I don't do it that way, because it wins
X% to be able to get arbitrarily more precision by moving out further.
X%	  PieDistance PieRadius gt or
X	  { null }
X	  { PieSliceWidth 2 div  PieInitialAngle
X	    Clockwise { add PieDirection sub } { sub PieDirection add } ifelse
X	    NormalAngle
X	    PieSliceWidth idiv } ifelse
X	def
X    } def
X
X% Update the highlighted slice to show the current menu value.
X
X    /PaintMenuValue { % - => - (Hilite current item, un-hilite prev one.)
X	PaintedValue	 PaintSlice
X	MenuValue        PaintSlice
X	/PaintedValue	 MenuValue store
X    } def
X
X% Paint highlighting on a menu slice. If it's null, then do nothing.
X% Draw an arrow, and a box around the key.
X
X    /PaintSlice { % key => -
X        dup null ne {	   			% key
X	  MenuGSave
X	    PieRadius dup translate
X
X% Draw an arrow pointing out in the direction of the slice.
X	    MenuItems exch get begin
X
X%   	    overlayerase
X	    MenuBorderColor setcolor
X 	    5 setrasteropcode
X
X	    HiLiteWithArrow? {
X	      gsave
X	        ang rotate
X	        newpath
X	        NumbRadius 0 moveto
X	        LabelRadius Gap sub			% r
X	        dup .6 mul dup PieSliceWidth 3 div sin mul lineto
X	        dup .9 mul 0 lineto
X	        .6 mul dup PieSliceWidth -3 div sin mul lineto %
X	        closepath
X                StrokeSelection {stroke} {fill} ifelse
X	      grestore
X	    } if
X
X% Highlight the key Thing.
X	    -4 2 X Y w h insetrrect rrectpath
X            StrokeSelection {stroke} {fill} ifelse
X	    end
X	  grestore
X        } {pop} ifelse				%
X    } def
X
X% Handle button up events. If we have children, then let the leaf
X% child menu handle the button up event. Otherwise, we handle it: If
X% it's a menu dictionary, then make it the child menu and show it.
X% Otherwise, execute the associated menu action, and send a /popdown
X% message to the root parent menu.
X
X    /UpProc {
X	  DragProc
X	  MenuValue getmenuaction dup type /dicttype eq {
X            /DeltaX 0 def /DeltaY 0 def % selection already made -- don't warp!
X	    /ChildMenu exch def
X	    ChildMenu /ParentMenu self put
X	    CurrentEvent /showat ChildMenu send
X	  } {
X	    pop
X	    % Ignore first mouse up if we're still in center of first menu
X	    ParentMenu null ne  MenuValue null ne  GotDown or or {
X              /DeltaX 0 def /DeltaY 0 def % don't warp!
X	      {
X	      % Find the parent menu
X	      self {
X	        dup /ParentMenu get dup null eq
X	        { pop exit }
X	        { exch pop } ifelse
X	      } loop
X	      % ^?^? (toodles [tm]!)
X	      /popdown exch send
X	      domenu
X	      } fork waitprocess % doesn't return
X	    } {
X	      % If we are still in menu center then map immediatly!
X                MapMenuEvent recallevent
X		MapMenu
X	    } ifelse
X	  } ifelse
X    } def
X
X% Handle menu button down events.
X
X    /DownProc {
X	/GotDown true store
X        DragProc
X    } def
X
X% Handle damage events. Gotta make sure the highlighted slice is
X% re-highlighted.
X
X    /DamageProc {
X      MenuGSave
X        damagepath clipcanvas
X        /paint self send
X        PaintedValue PaintSlice
X        newpath clipcanvas
X      grestore
X    } def
X
X% Construct menu event interests.  Use exclusivity so only the
X% top-most menu sees the events.
X
X    /makeinterests {
X        /MenuInterests [
X%            MenuButton /UpProc UpTransition null eventmgrinterest % X11/NeWS
X            MenuButton {UpProc pop} UpTransition null eventmgrinterest
X	    dup /Exclusivity true put
X	    dup /Priority 5 put
X%            MenuButton /DownProc DownTransition null eventmgrinterest
X            MenuButton {DownProc pop} DownTransition null eventmgrinterest
X	    dup /Exclusivity true put
X%	    MouseDragged /DragProc  null null eventmgrinterest
X	    MouseDragged {DragProc pop} null null eventmgrinterest
X	    dup /Exclusivity true put
X% 	    /EnterEvent /EnterProc null MenuCanvas eventmgrinterest
X 	    /EnterEvent {EnterProc pop} null MenuCanvas eventmgrinterest
X	    dup /Exclusivity true put
X% 	    /ExitEvent /ExitProc null MenuCanvas eventmgrinterest
X 	    /ExitEvent {ExitProc pop} null MenuCanvas eventmgrinterest
X	    dup /Exclusivity true put
X%	    /Damaged /DamageProc null MenuCanvas eventmgrinterest
X	    /Damaged {DamageProc pop} null MenuCanvas eventmgrinterest
X	    dup /Exclusivity true put
X	    dup /Priority -5 put
X%            AdjustButton /KerProc DownTransition null eventmgrinterest
X            AdjustButton {KerProc pop} DownTransition null eventmgrinterest
X	    dup /Exclusivity true put
X%            AdjustButton /ChunkProc UpTransition null eventmgrinterest
X            AdjustButton {ChunkProc pop} UpTransition null eventmgrinterest
X	    dup /Exclusivity true put
X% Kludge to refresh messed up retained menu canvases. Ssssh! Don't tell anyone.
X            PointButton {} DownTransition null eventmgrinterest
X%            PointButton /DamageProc UpTransition MenuCanvas eventmgrinterest
X            PointButton {DamageProc pop} UpTransition MenuCanvas
X	    eventmgrinterest
X%	    /MapMenu /MaybeMapMenu null MenuCanvas eventmgrinterest
X	    /MapMenu {MaybeMapMenu pop} null MenuCanvas eventmgrinterest
X	    dup /Priority -5 put
X	] def
X    } def
X
X  /getmenuaction { % index => action
X    dup null ne {
X	MenuActions 1 index MenuActions length 1 sub min get
X% Execute actions that are names! (This is so we can have references
X% to submenus (executable names) as actions, as opposed to having the
X% submenu object dict itsself!)
X	dup type /nametype eq { exec } if
X    } {nullproc} ifelse
X    exch pop
X  } def
X
Xclassend def
X
X/PieMenu SimplePieMenu def
X
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
X/LayeredPieMenu SimplePieMenu
Xdictbegin
X  /MenuArgs [] def
X  /MenuArg null def
X  /PaintedArg null def
Xdictend
Xclassbegin
X  % Need to make flipstyle a no-op because /new takes a different number
X  % of args, and actions might depend on MenuArg! Scratch that.
X  % Instead, let's just make a new instance of ourselves, of
X  % the same class.
X  /flipstyle {
X    0 1 MenuActions length 1 sub {
X	dup getmenuaction % fixed to use getmenuaction!
X	dup type /dicttype eq {
X	    /flipstyle exch send	% i menu'
X	    MenuActions 3 1 roll put	% -
X	} {pop pop} ifelse
X    } for
X    MenuArgs MenuKeys MenuActions /new ClassName load send
X    dup /LabelMinRadius LabelMinRadius put % hack
X  } def
X
X  /new {	% 	 args keys actions  =>  menu
X		%  -or-  args keys/actions (one array) => menu
X    /new super send begin
X      /MenuArgs exch def
X    currentdict end
X  } def
X
X  /showat {
X    /MenuArg null def
X    PaintedArg null ne MenuCanvas null ne and MenuWidth null ne and {
X      MenuGSave
X        PaintedArg PaintMenuArg
X      grestore
X    } if
X    /PaintedArg null store
X    /showat super send
X  } def
X
X  /DragProc {
X    ChildMenu null eq {
X      MenuGSave
X        PieRadius dup translate
X        CurrentEvent begin
X          XLocation DeltaX add
X          YLocation DeltaY add
X        end
X        SetMenuValue
X
X        MenuValue PaintedValue ne {
X          PaintMenuValue
X        } if
X        MenuArg PaintedArg ne {
X          PaintMenuArg
X        } if
X      grestore
X    } if
X  } def
X
X  /DamageProc {
X    MenuGSave
X        damagepath clipcanvas
X        /paint self send
X        PaintedValue PaintSlice
X	PaintedArg PaintArg
X        newpath clipcanvas
X    grestore
X  } def
X
X  /PaintMenuArg {
X    PaintedArg PaintArg
X    MenuArg PaintArg
X    /PaintedArg MenuArg store
X  } def
X
X  /PaintArg {
X    dup null ne {
X      MenuGSave
X	PieRadius dup translate
X	MenuBorderColor setcolor
X	5 setrasteropcode
X	100 string cvs
X	dup stringbbox points2rect
X	-.5 mul exch -.5 mul exch moveto
X	pop pop
X	show
X      grestore
X    } if
X  } def
X
X  /SetMenuValue { % x y => -
X    /SetMenuValue super send
X    /MenuArg
X      MenuValue null eq
X      MenuArgs length 0 eq or {
X        null
X      } {
X        PieDistance PieRadius 1 sub min NumbRadius sub
X	PieRadius NumbRadius sub div MenuArgs length mul floor
X	MenuArgs exch get
X      } ifelse
X    def
X  } def
X
X  /getmenuarg {
X    MenuArg
X  } def
Xclassend def
X
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
X/setdefaultmenu { % class => -
X  /DefaultMenu exch store
X  systemdict /rootmenu known {
X    %/rootmenu /flipstyle rootmenu send store
X  } if
X} def
X
XXNeWS? not
Xsystemdict /DontSetDefaultMenu known not and {
X  % Death to pulldown menus!
X  PieMenu setdefaultmenu
X} if
X
Xend
X
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//go.sysin dd *
if [ `wc -c < piemenu.ps` != 34084 ]; then
	made=false
	echo error transmitting piemenu.ps --
	echo length should be 34084, not `wc -c < piemenu.ps`
else
	made=true
fi
if $made; then
	chmod 664 piemenu.ps
	echo -n '	'; ls -ld piemenu.ps
fi
echo Extracting pullout.ps
sed 's/^X//' <<'//go.sysin dd *' >pullout.ps
X%!
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X% Class PulloutPieMenu
X% Copyright (C) 1988 by Don Hopkins (don@brillig.umd.edu)
X%
X% This program is provided free for unrestricted use and redistribution,
X% provided that the headers remain intact.  No author or distributor
X% accepts any responsibility for any problems with this software.
X%
X% PulloutPieMenu is a subclass of PieMenu that uses cursor distance
X% from the menu center to specify an argument to the menu selection.
X% Each menu key has an array of possible arguments, from which the
X% cursor distance selects the argument value.  The values in the
X% arrays are "Things" (cf. litemenu.ps & colordemo) that are painted
X% in the menu center as feedback.  The /new method of class
X% PulloutPieMenu takes the same arguments that regular menus do, plus
X% an additional array of argument arrays.  Each argument array
X% corresponds to a menu key.  If you give just one argument array, it
X% is used for all the keys, the same as with the array of actions.
X% You can use getmenuarg and getmenuargindex in your menu actions to
X% retrieve the argument displayed when the key was selected.
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
Xsystemdict begin
X
X% ------------------------------------ %
X% PulloutPieMenu
X
X/PulloutPieMenu PieMenu
Xdictbegin
X  /SliceWedges false def
X  /HiLiteWithArrow? false def
X  /PrinterMatch? false def
X  /ArgBorder 2 def
X  /EraseArgs? true def
X  /MenuArgs null def
X  /MenuArg null def
X  /MenuArgIndex null def
X  /PaintedArg null def
Xdictend
Xclassbegin
X
X  % [[args...]...] [keys...] [actions...] => menu
X  /new {
X    /new super send begin
X      dup length MenuKeys length lt {
X	[ exch aload pop % pad out args w/ last arg
X	  counttomark MenuKeys length exch sub {dup} repeat ]
X      } if
X      /MenuArgs exch def
X      currentdict
X    end
X  } def
X
X  % Need to make flipstyle a no-op because /new takes a different number
X  % of args, and actions might depend on MenuArg! Scratch that.
X  % Instead, let's just make a new instance of ourselves, of
X  % the same class.
X  /flipstyle {
X    0 1 MenuActions length 1 sub {
X	dup getmenuaction % fixed to use getmenuaction!
X	dup type /dicttype eq {
X	    /flipstyle exch send	% i menu'
X	    MenuActions 3 1 roll put	% -
X	} {pop pop} ifelse
X    } for
X    MenuArgs MenuKeys MenuActions /new ClassName load send
X    dup /LabelMinRadius LabelMinRadius put % hack
X  } def
X
X  /MenuGSave {
X    /MenuGSave super send
X    PrinterMatch? setprintermatch
X  } def
X
X  /DragProc {
X    ChildMenu null eq {
X      MenuGSave
X        PieRadius dup translate
X        CurrentEvent begin
X          XLocation DeltaX add
X          YLocation DeltaY add
X        end
X        SetMenuValue
X
X        MenuValue PaintedValue ne {
X          PaintMenuValue
X        } if
X        getmenuarg /PaintedArg load ne {
X          PaintMenuArg
X        } if
X      grestore
X    } if
X  } def
X
X  framebuffer /GLCanvas known { % SGI 4Sight?
X    % Paint menus on the overlay plane
X      /paint {
X	/paint super send
X	/PaintedArg load /PaintArg self send
X      } def
X  } {
X    /DamageProc {
X      MenuGSave
X	damagepath clipcanvas
X	/paint self send
X	PaintedValue PaintSlice
X	/PaintedArg load PaintArg
X	newpath clipcanvas
X      grestore
X    } def
X  } ifelse
X
X  /PaintMenuArg {
X    getmenuarg
X    dup null eq  /PaintedArg load null eq  EraseArgs? or or {
X      % The null...pop is to get around the fact that 4Sight's ThingSize
X      % recognizes [(string) /name] as a special case, and eats both,
X      % which hoses us if we call it with just a /name, but with a
X      % (string) on the stack before that.
X      null /PaintedArg load EraseArg pop
X    } if
X    dup PaintArg
X    /PaintedArg exch store
X  } def
X
X  /EraseArg { % thing => -
X    MenuGSave
X      dup null eq {
X	pop
X	PieRadius dup translate
X	MenuFillColor setcolor
X	0 0 LabelRadius Gap sub 3 sub 0 360 arc
X	fill
X      } {
X	PieRadius dup translate
X	MenuFillColor setcolor
X% dup /toggle3 eq {/foo dbgbreak} if
X	ThingSize
X	2 copy
X	-.5 mul exch -.5 mul exch
X	4 -2 roll
X	ArgBorder neg 5 1 roll insetrect % Some extra padding...
X	rectpath fill
X      } ifelse
X    grestore
X  } def
X
X  /PaintArg { % thing => -
X    MenuGSave
X      dup null eq {
X	pop
X	PieRadius dup translate
X	MenuBorderColor setcolor
X        MenuLineWidth setlinewidth
X	MenuLineCap setlinecap
X	MenuItems {
X	  begin
X	    gsave
X	      newpath
X	      ang PieSliceWidth 2 div sub rotate
X	      NumbRadius 0 moveto
X	      LabelRadius Gap sub 4 sub 0 lineto
X              MenuBorderColor setcolor
X	      stroke
X	    grestore
X	  end
X	} forall
X      } {
X	PieRadius dup translate
X	MenuTextColor setcolor
X        dup ThingSize
X	-.5 mul exch -.5 mul exch
X	ShowThing
X      } ifelse
X    grestore
X  } def
X
X  /showat {
X    PaintedArg null ne PaintedValue null ne and
X    MenuCanvas null ne and MenuWidth null ne and {
X      MenuGSave
X        /PaintedArg load EraseArg
X        /PaintedArg null store
X	null PaintArg
X      grestore
X    } if
X    /MenuArg null def
X    /MenuArgIndex null def
X    /showat super send
X  } def
X
X  /SetMenuValue { % x y => -
X    /SetMenuValue super send
X    /MenuArg
X      MenuValue null eq
X      {null true}
X      {MenuArgs MenuValue get dup length 0 eq} ifelse {
X        pop null
X	/MenuArgIndex null def
X      } {
X        PieDistance PieRadius 1 sub min NumbRadius sub
X	PieRadius NumbRadius sub div 1 index length mul floor
X	/MenuArgIndex 1 index def
X	get
X      } ifelse
X    def
X  } def
X
X  /getmenuargindex { % - => index
X    MenuArgIndex
X  } def
X
X  /getmenuarg { % - => Thing
X    /MenuArg load
X  } def
X
Xclassend def
X
Xend % systemdict
//go.sysin dd *
if [ `wc -c < pullout.ps` != 5590 ]; then
	made=false
	echo error transmitting pullout.ps --
	echo length should be 5590, not `wc -c < pullout.ps`
else
	made=true
fi
if $made; then
	chmod 664 pullout.ps
	echo -n '	'; ls -ld pullout.ps
fi
echo Extracting quickwin.ps
sed 's/^X//' <<'//go.sysin dd *' >quickwin.ps
X%!
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X%
X%  @(#)quickwin.ps
X%
X%  QuickWindow Class pie menu based window manager
X%  Copyright (C) 1988.
X%  By Don Hopkins.
X%  All rights reserved.
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% August 28, 1988  Don Hopkins
X%    Made the menus shared by all instances of the class.
X%    Put in a kludge to keep "spin" from trashing everybody's frame menu.
X%    (If you want to learn how to write good NeWS code, don't look at spin.)
X%    Added the DontSetDefaultWindow flag.
X%
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Xsystemdict begin
X
Xsystemdict /PieMenu known not {
X  (NeWS/piemenu.ps) LoadFile pop
X} if
X
X/QuickWindow LiteWindow
Xdictbegin
X  /Retained? framebuffer newcanvas /Retained get def
X  /CheapIcon? true def
Xdictend
Xclassbegin
X
X    /stretchtopright {
X      non-iconic
X      FrameX  FrameY
X      BBoxFromUser reshape
X    } def
X
X    /stretchtopleft {
X      non-iconic
X      FrameX FrameWidth add  FrameY
X      BBoxFromUser reshape
X    } def
X
X    /stretchbottomright {
X      non-iconic
X      FrameX  FrameY FrameHeight add
X      BBoxFromUser reshape
X    } def
X
X    /stretchbottomleft {
X      non-iconic
X      FrameX FrameWidth add  FrameY FrameHeight add
X      BBoxFromUser reshape
X    } def
X
X    /stretchtop {
X      non-iconic
X      /GA_value FrameX def
X      /GA_constraint 0 def
X      FrameX FrameWidth add  FrameY
X      BBoxFromUser reshape
X    } def
X
X    /stretchbottom {
X      non-iconic
X      /GA_value FrameX def
X      /GA_constraint 0 def
X      FrameX FrameWidth add  FrameY FrameHeight add
X      BBoxFromUser reshape
X    } def
X
X    /stretchleft {
X      non-iconic
X      /GA_value FrameY def
X      /GA_constraint 1 def
X      FrameX FrameWidth add  FrameY FrameHeight add
X      BBoxFromUser reshape
X    } def
X
X    /stretchright {
X      non-iconic
X      /GA_value FrameY def
X      /GA_constraint 1 def
X      FrameX  FrameY FrameHeight add
X      BBoxFromUser reshape
X    } def
X
X    /movevertical {
X      /GA_constraint 0 def
X      slide
X    } def
X
X    /movehorizontal {
X      /GA_constraint 1 def
X      slide
X    } def
X
X    /flipmove {
X      gsave
X      	framebuffer setcanvas
X	CurrentEvent begin XLocation YLocation end
X	unmap
X	Iconic? {
X	  exch FrameWidth 2 div sub exch FrameHeight 2 div sub
X	  /FrameX 2 index def /FrameY 1 index def
X	  FrameCanvas
X	} {
X	  exch IconWidth 2 div sub exch IconHeight 2 div sub
X	  /IconX 2 index def /IconY 1 index def
X	  IconCanvas
X	} ifelse
X	setcanvas matrix defaultmatrix setmatrix 2 copy movecanvas
X	flipiconic
X	move
X	slide
X      grestore
X    } def
X
X    /non-iconic {
X      Iconic? { flipiconic } if
X    } def
X
X    /reshapefromuser-open {
X      non-iconic
X      reshapefromuser
X    } def
X
X    /flipiconic {
X	% Don't retain the frame canvas when iconic!
X        Retained? CheapIcon? and {
X	  IconCanvas /Retained Iconic? not put
X	  FrameCanvas /Retained Iconic? put
X	} if
X	/flipiconic super send
X    } def
X
X    /CreateFrameCanvas {
X      /CreateFrameCanvas super send
X      /Retained? FrameCanvas /Retained get def
X    } def
X
X    /CreateFrameMenu { % - => - (Create frame menu)
X	% Note: Store menu in class to share menus, especially if retained.
X	/FrameMenu ClassFrameMenu def
X    } def
X
X    /CreateIconMenu { % - => - (Create icon menu)
X	% Note: Store menu in class to share menus, especially if retained.
X	/IconMenu {FrameMenu} def
X    } def
X
X%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
X
X% The menus shared by all instances of the class:
X
X        /MenuFont /Courier findfont 12 scalefont def
X
X	/FrameDebugMenu [
X	  (userdict) {
X	    { clear
X	      ParentDictArray length 1 add {end} repeat
X	      /OllieNorthIsAHero dbgbreak
X	    } fork pop
X	   }
X
X	  (ThisWindow) {
X	    { clear
X	      { /CatsupIsAVegetable dbgbreak } ThisWindow send
X	    } fork pop
X	  }
X
X	] /new PieMenu send def
X	FrameDebugMenu /MenuFont MenuFont put
X	FrameDebugMenu /flipstyle {currentdict} put
X	FrameDebugMenu /LabelMinRadius 5 put
X
X	/FrameEtcMenu [
X	    (zap)		{/destroy ThisWindow send}
X	    (debug)		FrameDebugMenu
X	] /new PieMenu send def
X	FrameEtcMenu /MenuFont MenuFont put
X	FrameEtcMenu /flipstyle {currentdict} put
X	FrameEtcMenu /LabelMinRadius 5 put
X
X	/FrameMoveMenu [
X	  /move_v		{/movevertical ThisWindow send}
X	  /move			{/slide ThisWindow send}
X	  /eye			{/flipmove ThisWindow send}
X	  /move_h		{/movehorizontal ThisWindow send}
X	] /new PieMenu send def
X        FrameMoveMenu /flipstyle {currentdict} put
X        FrameMoveMenu /LabelMinRadius 15 put
X        FrameMoveMenu /LabelRadiusExtra 0 put
X        FrameMoveMenu /SliceWedges false put
X        FrameMoveMenu /HiLiteWithArrow? false put
X
X	/FrameStretchMenu [
X	  /stretch_h		{/stretchtop ThisWindow send}
X	  /stretchNE		{/stretchtopright ThisWindow send}
X	  [/stretch_v 4 0]	{/stretchright ThisWindow send}
X	  /stretchSE		{/stretchbottomright ThisWindow send}
X	  /stretch_h		{/stretchbottom ThisWindow send}
X	  /stretchSW		{/stretchbottomleft ThisWindow send}
X	  [/stretch_v 4 0]	{/stretchleft ThisWindow send}
X	  /stretchNW		{/stretchtopleft ThisWindow send}
X	] /new PieMenu send def
X        FrameStretchMenu /flipstyle {currentdict} put
X        FrameStretchMenu /LabelMinRadius 5 put
X        FrameStretchMenu /LabelRadiusExtra 0 put
X        FrameStretchMenu /SliceWedges false put
X        FrameStretchMenu /HiLiteWithArrow? false put
X
X	/ClassFrameMenu [
X	    [(\255) /Symbol findfont 12 scalefont]
X		    		{/totop ThisWindow send}
X	    (Paint!)
X				{/paint ThisWindow send}
X	    (Move\274)
X	    			FrameMoveMenu
X	    (Etc\274)		FrameEtcMenu
X	    [(\257) /Symbol findfont 12 scalefont]
X	    			{/tobottom ThisWindow send}
X	    (Shape!)		{/reshapefromuser-open ThisWindow send}
X	    (Grab\274)
X	    			FrameStretchMenu
X	    /eye		{/flipiconic ThisWindow send}
X	] /new PieMenu send def
X	ClassFrameMenu /MenuFont MenuFont put
X	ClassFrameMenu /LabelMinRadius 10 put
X	ClassFrameMenu /LabelRadiusExtra 10 put
X
X
X	% Make a copy of ourselves if somebody tries to change us!
X	% (Yes this is a hack, but otherwise "spin" messes up everybody
======== END OF cyber.shar.splitaa ========