Inter-Office Memorandum
To  Cedar Interest  Date December 21, 1982
From Scott McGregor  Location Palo Alto
Subject The Viewers Window Package Organization PARC/ISL
Filed on: [Indigo]<Cedar>Documentation>ViewerDoc.Tioga and ViewerDoc.Press.
Documents: [Indigo]<Cedar>Viewers>Viewers.df, as exported by the Cedar boot file.
The Viewers Window Package
Disclaimer
This document is currently in progress and hence is incomplete (as witnessed by a number of sections not yet written). It reflects the state of the Viewers package for Cedar version 4.0. You may be able to find a more recent version on [Indigo]<CedarViewers>Viewers>ViewerDoc.tioga.
Introduction
The Viewers Window Package is the arbiter of the user input and display hardware in the Cedar programming environment. It provides the illusion to the programmer that there is a private display, mouse and keyboard associated with each application, while allowing the user to simultaneously interact with many such applications.
The basic object manipulated by client programs and visible to the user is the viewer; a rectangular area with arbitrary contents which may be made visible on the user display. A viewer takes its name in that it allows the human user to view and interact with the data associated with a Cedar application. The underlying applications software has complete control over the displayed contents of a viewer and has available a rich user interface for user input. The screen position and size of a viewer may be modified by the user as well as under program control.
This documentation is written for the programmer intending to use the Viewers Window Package to build a new application. It is organised along the broad areas of functionality that the Viewers system provides and attempts to explain design theory and some pragmatics. For examples of usage, see the references within each section, and for exact details consult the interfaces directly. One point of notation: used throughout this document, client refers to a program calling the Viewers interfaces, whereas user refers to the human invoking Viewers operations with the mouse and keyboard.
Screen Layout
The User Desktop
From the user point of view, the black and white screen is divided into four areas. The top quarter inch of the display is used for the messages and a small set of system command buttons. The bottom of the display is a variable height area reserved for displaying icons, which are small pictorial representations of normal viewers made iconic to conserve screen space. The remainder of the display is divided into left and right columns with a moveable partition between them. The user may optionally attach a color display, which is equivalent to an additional color column.
Unlike many window packages, viewers do not normally overlap, but instead spread out to cover as much as possible of the available space on the user display. Within a column, the height of a particular viewer is determined by satisfying a number of constraints set by the Viewers system, the implementing program and the user. Viewers constraints include balancing of the columns; i.e. viewers will be expanded so that the entire column area is used, and that no viewer is smaller than the height required for the caption and command menu at the top of each viewer. A client program may specify a height hint in the viewer instance's openHeight field, which will be honored if it doesn't conflict with other constraints. In addition, the user may set a height hint that overrides the openHeight value by invoking the Adjust menu command. User-set hints are discarded when a viewer is made iconic.
A fine point: The current implementation does not deal particularly well with overcontrained columns; i.e. when the sum of the Viewers enforced heights plus the client openHeight hints exceeds the height of the column. In order to solve the conflicting constraints, each viewer is given one nth of available column height. Ideally, Viewers should either pro-rate the existing space according to the client requests or force some of the viewers in the overconstrained column to become iconic.
Internally, the tree of viewers is partitioned into four subtrees, corresponding to static (typically those viewers with a permanent, fixed position on the screen), the left column, the right column, and the color display. Viewers in the static subtree include all icons, the message window at the top of the display, as well as the system buttons located in the upper right hand corner.
The boundary between the left and right columns as well as the height of the columns may be set by invoking the Adjust menu command in any viewer and then sliding the mouse across the column boundary. The column height is quantized to the height of each row of icons, permitting up to two rows of icons or as few as none. Icons are displayed behind the columns; in other words, viewers in a column overlapping the display of an icon will hide the icon until the user shortens the column, or removes all the viewers from that column.
Multiple Desktops
Users can save configurations of viewers in a special viewer called a desktop. The user can then move back and forth between different configurations of viewers with a simple command. There is always one desktop which represents the configuration of viewers currently on the screen. This desktop (called the current desktop) is indicated on its icon by having its name inverted. The user can "fly" to another desktop by middle clicking the desktop icon while holding down the control key. The viewers and icons on the screen will be stuffed into the current desktop, to be replaced by the viewers and icons in the new desktop. The new desktop then becomes current.
To get a new desktop, type "Desktop 'name'" to the UserExec. This will create an icon that looks like a minature screen. The first desktop created becomes the current one. A second desktop must be created before you can move to a new desktop. When you fly to the new desktop, only desktops and the UserExec will go with you, all other viewers will be stored in hyperspace. Viewers can be brought over one by one as described below.
To move a viewer from another desktop to the screen, open the desktop icon and left-click the button representing the viewer. This will move the viewer from that desktop onto the screen. If the viewer is already on the screen but iconic, clicking the button will open the viewer. Clicking the button with the shift key down causes the viewer to grow to full column. Viewers can be added to a desktop by selecting the viewer and clicking "AddSelected" in the desktop's menu. This will cause the viewer to be removed from the screen.
To move an individual viewer from the screen onto a particular desktop, open the desktop icon, select the viewer and left-click "AddSelected" in the menu of the desktop. The viewer will then disappear from the screen. You can remove a viewer from a desktop by clicking its button with control held down. If this was the last reference to the viewer, it will automatically be moved back onto the screen. Destroying a desktop viewer may also cause hidden viewers to appear on the screen.
Although some viewers may be inaccessible to the user because they are on different desktops, all viewers are accessible to client programs via ViewerOps.EnumerateViewers. This means that programs don't have to enumerate desktops to see all of the viewers. The bit "offDesktop" will tell the client program whether the viewer is currently accessible to the user. Opening, closing, repositioning, or blinking a viewer will automatically move it onto the screen, whether or not it was on the screen before. Painting a viewer will not. If the client program wants to manually move a viewer onto the screen, it can do so with ViewerOps.ChangeColumn[viewer, {left, right, color}]. All viewers are stored off the screen as icons, therefore a program should only have to worry about manually moving viewers onto the screen if it wants the user to see it repaint an icon.
Viewers
The display of a viewer consists of two nested rectangles. The outer rectangle bounds the viewer window overhead, consisting of space for an optional black border around the viewer, an optional scrollbar space on the left, a black caption bar at the top, and an optional menu below the caption containing an arbitrary number of menu lines. The inner rectangle defines the viewer client area, which is available to an application for display of its data.
Each viewer has a parent, a sibling and a child viewer, any of which may be NIL. Viewers may be recursively nested within (i.e. children of) other viewers, in which case display of the caption and menu will be supressed and no space reserved in the outer window rectangle.
The coordinates for the window and client rectangles are computed with respect to the enclosing parent's client rectangle origin. If the viewer has no parent, it is known as a top level viewer and its rectangle coordinates are with respect to the lower right hand corner of the display. A viewer may extend outside of its parent's client rectangle, in which case it will be clipped during display. Sibling viewers may not overlap.
Viewer Classes
The Viewers package allows the programmer to create a class of viewer, all instances of which will share code for common operations. A viewer class is a record that defines a set of operations and parameters common to all viewers of a particular user defined type. For example, the Tioga document preparation system creates a viewer class for all of the editable text viewers, so that each instance of a Tioga viewer uses the same code to display, scroll, accept input from the user and so forth.
A viewer class record (as described in ViewerClasses.mesa) contains the following information:
flavor: ViewerClasses.ViewerFlavor ← NIL;
Each class has a unique atom which associates a name with the class record.
init: ViewerClasses.InitProc ← NIL;
During the creation of a new viewer, this procedure is called in order to permit the client to initialise private data structures. The viewer will not appear on the screen until the procedure returns. Class implementors should use this procedure to insert menu entries and add sub-viewers.
paint: ViewerClasses.PaintProc ← NIL;
The Viewers package assumes that the bitmap is write-only and that the client can reconstruct its screen image on demand. Whenever the information on the screen for a particular viewer becomes invalid, the PaintProc will be called by the system to restore the correct display. The PaintProc is passed a graphics context clipped to the bounds of the viewer, a whatChanged parameter which the client may use to encode private information about what to update, and a clear boolean that indicates whether the viewer has been whitened before the paint call. There is a complete section on painting elsewhere in this document.
destroy: ViewerClasses.DestroyProc ← NIL;
The Cedar garbage collector normally deallocates storage associated with a viewer when it is destroyed, but sometimes a client finds it convenient or necessary to free resources or note the destruction of a viewer instance explicitly. This procedure is called just before the viewer is removed from the viewer tree.
notify: ViewerClasses.NotifyProc ← NIL;
Mouse and keyboard input from the user is communicated to a viewer as a list of results described in a tip table (see the tipTable field below). This procedure will be called whenever an input event for a particular viewer is received.
tipTable: TIPUser.TIPTable ← NIL;
A TIP Table is a list of productions, mapping mouse and keyboard operations into a list of results meaningful to the client. Please see the section on Mouse and Keyboard input for more information.
modify: ViewerClasses.ModifyProc ← NIL;
Keyboard input depends on a viewer owning the input focus described later. This procedure is called whenever a viewer loses or acquires the input focus in order to provide feedback, such as a blinking caret.
set: ViewerClasses.SetProc ← NIL;
Some viewer classes choose to implement this interface as a way of setting the contents or state of a viewer. The data and op arguments may be interpreted any way the client chooses and the finalise parameter determines whether the new information should be reflected on the display. Tioga, Buttons, and Labels are three viewer classes which implement this interface to set the text contents when passed a ROPE or REF TEXT.
get: ViewerClasses.GetProc ← NIL;
A viewer class may implement this interface as a means of allowing a client to query the contents or state of a viewer. Like the SetProc, the op parameter may be interpreted by the class implementor as they see fit.
scroll: ViewerClasses.ScrollProc ← NIL;
The ScrollProc is called with an operation parameter, corresponding to scrolling up, scrolling down, thumbing to a particular place in the data structure, or querying the client as to its current scroll position. For the scroll up and scroll down operations, the amount passed is the user's request, measured in points. It is up to the client to interpret the amount with respect to their internal data structures, adjust their display data structures and request repaint. For the thumb operation, the amount passed is the percentage to scroll into the viewer; i.e. 47 would mean to start the top of the display 47% into the data displayed, as interpreted by the client. The query operation requests that the client return two numbers for feedback to the user, corresponding to the percentage of the data displayed at the top and bottom of the viewer; i.e. if the entire data structure were visible, the client would return 0 and 100. If the client cannot reasonably compute the query percentages or chooses not to, then it may simply return from the ScrollProc when this operation is encountered.
menu: Menus.Menu ← NIL;
A viewer may optionally display a menu of commands underneath the caption. See the section on Menus for more information.
icon: Icons.IconFlavor ← document;
When a viewer is iconic, the client PaintProc is intercepted and is instead displayed as a small picture, determined by the IconFlavor set here. The Icons interface has an enumerated set available, as well as an interface to create new icons. The client may also paint their own icon using the CedarGraphics facilities by setting the iconFlavor to private, which will cause the painting of iconic viewers to no longer be intercepted. If the iconFlavor is private, then it is up to the client to notice that they are iconic and paint appropriately.
cursor: Cursors.CursorType ← textPointer;
Viewers will display a cursor when moved over a viewer, determined by the value here. The Cursors interface has an enumerated set available, as well as an interface to create new cursors.
clipChildren: BOOLFALSE;
The normal paint order for viewers with embedded children is the parent first and then the children. There is normally no protection from the parent painting over a child unless this bit is set to true, in which case all child viewers will be clipped (excluded) from the context supplied to the parent. This field is not defaulted to true, since it makes normal CedarGraphics operations computationally expensive for the parent.
The following viewer class fields are either rarely used or not currently implemented. They are documented here for completeness:
save: ViewerClasses.SaveProc ← NIL;
The SaveProc is called when the client is expected to write the private data structure to a disk file. This is currently only used by Tioga.
copy: ViewerClasses.CopyProc ← NIL;
The data associated with a particular viewer is private to the class implementation and hence the Viewers package doesn't know how to replicate the structure. This procedure passes an old viewer and a new viewer and requests that the data for the new viewer be made the same as the old.
caption: ViewerClasses.CaptionProc ← NIL;
The caption normally displays the name and status of the viewer. If this is not acceptable to a particular client, then they may implement this procedure and paint the caption themselves. The graphics context passed is clipped to the caption area.
coordSys: ViewerClasses.CoordSys ← bottom;
The coordinate system of the graphics context passed to the viewer PaintProc will normally have its origin at the lower left corner of the viewer, with x and y increasing to the right and upward. If the coordSys is set to top, then the origin will be set to the top left corner with y increasing downward.
bltContents: BOOLEANFALSE;
This is currently unused.
paintRectangles: BOOLEANFALSE;
This is currently unused.
It is important to note that the implementor of a viewer class can default any of the fields if they choose not to provide that particular functionality; the system will do the right thing with requests on viewers that do not implement a particular operation.
The programmer creates a new viewer class by allocating and initialising a ViewerClasses.ViewerClassRec and then calling ViewerOps.RegisterViewerClass, passing the class record and a unique atom which names the new class. This operation creates a binding between the class operations and any newly created viewer instances (see the Viewer Instances section below). Subclassing (as in SmallTalk) is not directly supported by the system; the programmer must explicitly copy and modify an existing viewer class.
A simple example of creating and registering a viewer class can be found on [Indigo]<Cedar>Viewers>LabelsImpl.mesa.
Viewer Instances
Once a Viewer Class is defined, instances may be created which will inherit information from the class. Many of the predefined viewer classes (listed in the next section) provide instance creation operations, otherwise a client may call ViewerOps.CreateViewer, passing the class and initial data for the instance.
A ViewerClasses.ViewerRec defines the data associated with each viewer instance. During viewer creation, the client may initialise some of the fields, the Viewers package will initialise others, with the rest defaulting. The remainder of this section describes the data structure in some detail, and is of particular interest to a client implementing a viewer class or creating a tool comprised of many embedded viewers.
Each viewer instance maintains a pointer back to its class data record:
class: ViewerClass ← NIL
The class field is initialised by Viewers during instance creation and remains constant for the lifetime of the viewer.
Each viewer contains two rectangles, describing the outer boundary of the viewer and a properly contained inner area available for displaying client information:
wx, wy, ww, wh: INTEGER ← 0,
cx, cy, cw, ch: INTEGER ← 0
The wx and wy fields define the corner of the viewer with respect to its parent's client origin. In the case of a top level viewer, wx and wy will be with respect to the bottom left corner of the display screen. The ww and wh fields describe the width and height of the viewer, measured in screen pixels. The cx, cy, cw, and ch fields define an inner rectangle and represent the clipping boundary for display of the client information. cx and cy are measured from the parent's client origin, just as the wx and wy fields. The client should initialise the wx, wy, ww, and wh fields during viewer creation if and only if the viewer will be embedded in a parent viewer, since the column constraint algorithms will recompute these values. Since viewer position and other information is cached by Viewers, clients should never directly set any of the viewer rectangle values, but instead should use routines in the ViewerOps interface to change the size or position of a viewer.
Other viewer fields of interest to clients include:
data: REF ANYNIL
The implementor of a viewer class may associate instance data with a viewer in this field. Note that only the class implementor may access the data field; other clients should use the property list associated with each viewer.
name: Rope.ROPENIL
Each viewer has a text name associate with it, which in the case of top level viewers, is displayed in the caption. The client may modify the viewer name, but must be sure to repaint the caption if applicable (via ViewerOps.PaintViewer[viewer: viewer, hint=caption]).
border: BOOLTRUE
An embedded viewer is displayed with a one-bit wide black border if the border field is set. Top level viewers are always displayed with a border.
tipTable: TIPUser.TIPTable ← NIL
The TIPTable defines how each viewer interprets mouse and keyboard input and is copied from the class record when a viewer is created (there is a later section describing the mouse and keyboard input mechanism in more detail). In some cases, the client may wish to change the behaviour of a particular viewer and may do so by modifying this field. A fine point: if a viewer owns the input focus, then its TIPTable is cached by the notifier, which presently must be reset by releasing and then recapturing the input focus.
file: Rope.ROPENIL
Some viewers chose to associate a backing file with their data structures. While this logically belongs with the implementors data, it appears in the viewer instance data as a convenience to clients. It may be removed in the future.
menu: Menus.Menu ← NIL
A top level viewer may optionally have a menu of commands permanently displayed below the caption. Ideally, the client should pass a menu when a viewer is created. To add a menu to an existing viewer, the client must use ViewerOps.SetMenu to reset internal rectangle caches and to repaint the new menu on the display.
icon: Icons.IconFlavor ← tool
When a top level viewer is made iconic, it no longer displays the client data, but instead appears as a small symbol, easily recognisable by the user. The instance's icon field is normally initialised from the viewer's class, but may be overridden by the client during viewer creation. The Icons interface provides routines to access existing Viewers icons (Viewers includes symbolic pictures for a document, tool, typescript, and a file drawer) or to create new icons from either a procedure or a set of bitmaps stored in a file. The client may specify whether an icon is to be labelled by Viewers with the viewer name. If the instance's icon field is set to private, then the client PaintProc will be called even though the viewer is iconic, which is how the clock icon displays the current time.
column: ViewerClasses.Column ← left
When a viewer is created, the client may specify in which column a viewer will be displayed. Clients should only change this field in an existing top level viewer by calling ViewerOps.ChangeColumn.
scrollable: BOOLTRUE
Viewers will allocate a scrollbar area on the left hand edge of a viewer as well as provide appropriate user feedback if this bit is specified during viewer creation. The actual scrolling operation are performed by calling the viewer's class ScrollProc.
iconic: BOOLTRUE
Clients may set the iconic bit during the creation of a top level viewer in order to initially display the viewer as iconic at the bottom of the display or open in its column. A client may not change the iconic bit for an existing viewer, except by calling ViewerOps.OpenIcon or ViewerOps.CloseViewer.
newVersion: BOOLFALSE
A client may test to see if edits have been made to a viewer by testing the newVersion bit. Viewer implementors should use ViewerOps.SetNewVersion to set the newVersion bit and display the "[New Version]" message in the viewer caption.
newFile: BOOLFALSE
A client may test to see if there is currently no existing backing file for a viewer by testing the newFile bit. Viewer implementors should use ViewerOps.SetNewFile to set the newFile bit and display the "[New File]" message in the viewer caption.
offDeskTop: BOOLEANFALSE
A client may test to see if the viewer is currently accessible to the user. ViewerOps.ChangeColumn[viewer, {left, right, color}] will move it back onto the screen.
openHeight: INTEGER ← 0
A client may set the value of openHeight to be the desired vertical space taken up by a viewer when open in a column. The window manager will attempt to honor the request, but may give more or less space than requested.
parent: ViewerClasses.Viewer ← NIL
Each viewer that is nested within another viewer keeps track of its parent through this field. This field will be nil for top-level viewers.
sibling: ViewerClasses.Viewer ← NIL
Viewers of equal depth within a tree are linked via the sibling field.
child: ViewerClasses.Viewer ← NIL
A viewer may have children nested within it.
props: Atom.PropList ← NIL
Clients may associate arbitrary data and properties with a viewer by adding them to the property list. The AddProp and FetchProp operations in ViewerOps are the recommended way of accessing the viewer property list.
A number of fields in the viewer record are private to Viewers or are not particularly of interest to most clients. They are included here for completeness:
lock: ViewerClasses.Lock ← [NIL, 0]
The viewer data structure may be locked with non-exclusive read or exclusive write semantics, making use of the lock data structure within each viewer instance. The client should never access this field directly, but should use routines provided in the ViewerLocks interface. A more detailed treatment of locking may be found elsewhere in this document.
visible: BOOLTRUE
The Viewers package maintains a private visibility hint to speed some repainting operations. Clients should not rely on the value of this field.
offDeskTop: BOOLFALSE
Some viewers may be on other than the current desktop, in which case the offDeskTop bit will be set.
destroyed: BOOLFALSE
A viewer is destroyed by calling ViewerOps.DestroyViewer, at which time it is removed from the viewer tree and this field is set to false.
saveInProgress: BOOLFALSE
Some clients need to know when a Save operation is currently pending for a viewer, and may examine the state of the saveInProgress field. Note that the newVersion bit remains set until completion of a Save.
init: BOOLFALSE
Viewers maintains a private hint indicating that a new viewer has been properly initialised. It has no other uses.
inhibitDestroy: BOOLFALSE
The inhibitDestroy bit prevents the user from invoking the Destroy operation in a top-level viewer menu. This field will be removed in future releases, so clients should not depend on it.
guardDestroy: BOOLFALSE
The Destroy menu command for top-level viewers is normally guarded iff there are new edits. If the client wishes the Destroy menu command to always be guarded, then they may set this bit.
link: ViewerClasses.Viewer ← NIL
Linked viewers are connected via a ring data structure. Currently, linked viewers are not completely supported by the system, but this field is included for clients to implement linking semantics, as in Tioga.
position: INTEGER ← 0
The position field is a private value used by Viewers for icon positioning and adjusting of viewer size when open in a column.
Predefined Viewer Classes
Listed below is a set of viewer classes for client use with implementations provided in the Cedar boot file.
Buttons
Buttons are a class of viewers that display a text label and call a procedure when the user clicks the mouse over them. Buttons are usually created within a container (see below) as part of a tool, either directly throught the Buttons interface or as part of a higher level object created with the ChoiceButtons interface. Parameters to the client procedure include the button viewer, the mouse button that invoked the button, and the state of the shift and control keys at the time of invocation.
Containers
A container is a viewer that permits other viewers to be recursively embedded and scrolled, and is created using the Containers interface. Routines are also provided to constrain embedded viewers to be clipped to the edges of the parent container. Unlike most viewer classes, the coordinate system inside a container has its origin at the upper left corner, with the y coordinate increasing in the downward direction. A container initially has no menu, but many tool implementors find it convenient to include a menu of tool-related commands when creating a container.
Labels
A label is a simple kind of viewer that displays a text message in a single font. The label may not be selected or edited, but has the advantage over Tioga text viewers (described below) of having very low data structure overhead.
Rules
A rule viewer displays as a rectangle of a single color on the display, and is created using the Rules interface. They are useful for creating line graphics when designing the layout of tools.
Text
Text viewers are implemented by the Tioga Document Preparation system described in detail on [Indigo]<Cedar>Documentation>TiogaDoc.tioga. The ViewerTools interface provides a set of operations that allow a client program to create text viewers as well as to fetch and store their contents. There are a great many additional operations supported by the Tioga editor, exported by the TiogaOps interface, which is described in the Tioga documentation.
Implementation Guidelines
The procedures and variables in a viewer were designed to support a particular style of implementation for new classes. Many of the procedures and variables were added specifically to help solve some general problem of concurrency or user interaction. Implementors are not required to use these procedures, but they should only depart from them when they have good reasons.
The best way to write a user application that uses Viewers is to first write a applications package accessible to client programs and then make a thin veneer over it for users. It is tempting to tailor your implementation to the user interface, but this temptation should be resisted. No matter how user-oriented your program is, some user some day will want to write a program that uses your application directly. It is best that you prepare for that eventuality now.
There are four different ways that a particular function in your program could be invoked: notification of an user event through the NotifyProc, a call on a pre-defined function in the Viewers class (such as set, get, and save), invokation through a button or menu item on the viewer, and a client call on an interface you export. If you use more than one of these paths to invoke a function you should be absolutely certain that they all have exactly the same semantics. The best way to do this is to have them all call the same procedure. Thus the NotifyProc that handles special user actions should do no more than gather parameters and dispatch to procedures that are defined in an interface exported by your program. The same should be true of procedures that are invoked with buttons and menus.
The functions `create' and `destroy' are special functions in the Viewers world. All of the creation and destruction that is necessary for a particular Viewers class should happen in the class's InitProc and DestroyProc. In particular it is very important that all of the menu construction, sub-viewer creation and private data initialization happen in the InitProc. This allows the Viewers package to create and destroy instances of a class without having to know about interfaces exported by the class's implementation. This is important since opening a desktop sometimes requires the re-creation of a viewer that the user had destroyed. All that the Viewers package can do is call ViewerOps.CreateViewer[viewerFlavor, info: [name: viewerName]] and hope that this is sufficient to create and initialize the viewer. Application tools should create their own viewer's class just so they can have their own InitProc, even if there is never more than one instance of the tool. Similarly, ViewerOps.DestroyViewer[viewer] should be all the Viewers package needs to make sure that the viewer has cleaned up all of its internal data structures. (Cleaning up internal data structures includes breaking circular links so the garbage collector will reclaim the storage.)
Mouse and Keyboard Input
<not yet written>
Locking
The ViewerLocks interface defines an interlocking mechanism to arbitrate access to the Viewer window tree, viewer columns, as well as individual viewers. A particular viewer may be locked for reading or for writing. A read request implies that the calling code would like to examine values in the ViewerClasses.ViewerRec and insure that these values are invariant for the duration that the read lock is held. Any number of clients can simultaneously hold read locks on a single viewer. A write lock is an exclusive access to a viewer for the implied operation of modifying one or more of the fields in the ViewerClasses.ViewerRec.
Locks are process re-entrant, meaning that a single process may request a lock multiple times without deadlock; i.e. if a process currently has write access to a viewer, it may in addition request read or write access (this obviously doesn't grant any new permissions, but is useful when a client has already locked a viewer and wishes to call code that may attempt a lock). Due to the ordering of the read and write resources, a process holding a read lock may not request a write lock on the same viewer without first releasing the read lock.
The viewer tree as well as the particular columns are another set of resources that may be locked. Locking a column is equivalent to (but not implemented as) locking all of the viewers in that column. Locking the viewer tree is equivalent to locking all of the columns for write in addition to the root pointer for the tree. The viewer tree must be locked by the client any time a top level viewer changes size or position in the tree that crosses column boundaries. Since all painting operations are protected by a read lock on the updated viewer, the viewer tree lock will not be granted until painting activity has subsided.
The hierarchy of locks in the viewers window package, from highest to lowest is: the viewer tree, a write lock on a column, a write lock on a particular viewer, a read lock on a column, and a read lock on a particular viewer. A client may only request a new lock if is at the same or lower logical level. The documentation in the viewer interfaces has been (will be) updated to show which locks the operation requires, so that the client can avoid deadlocks.
A fine point: if a client program needs to lock multiple viewers, it must acquire the lock for each viewer in the proper order. Routines are provided below that correctly sort the parameter list for up to three viewers; otherwise the client must order the lock requests so as to lock the viewers in ref order (treating the viewer ref as a long cardinal and locking the highest first). Columns must be locked in the order {static, left, right, color}.
Users are advised to make use of the call-back operations provided when they need to perform locked operations on viewers, and not try and use the locking primitives directly. The suggested usage is to create a local procedure containing the critical code, which is passed to the routines below. The local procedure will then have full access to all of the variables in the outer procedure.
Painting
<not yet written>
Icons
<not yet written>
Menus
<not yet written>
Pragmatics
<not yet written>
Interface Summary
Buttons
Buttons are a class of viewers that display a text label and call a procedure when the user clicks the mouse over them. This interface provides routines to create and destroy buttons, as well as the ability to change the visual appearance of the text label.
Carets
Implementors of text editors (and maybe some other types of editors) provide feedback to the user where text insertion will go by means of a blinking caret on the screen. The Carets interface allows a viewer class implementor to display blinking carets without having to worry about issues of timing, clipping, etc.
ChoiceButtons
When building tools and other applications using Viewers, clients often require user interface abstractions for enumerated types, string parameters the user can edit, and boolean values. ChoiceButtons is a high level interface based on Buttons and ViewerTools that provides these abstractions as primitives.
Containers
A client often wishes to build a tool that consists of several viewers associated with each other. Containers are a very simple viewer class that permit other viewers to be recursively embedded and scrolled. Routines are provided to constrain embedded viewers to be clipped to the edges of the parent container.
Cursors
The Cursors interface exports a set of bitmaps suitable for display in the hardware cursor as well as primitives enabling a client to create new cursor bitmaps. The cursor bitmaps have a logical hot spot associated with them that defines the single point in the cursor where the user is pointing; e.g. for a bullseye cursor the hot spot is in the center whereas the text pointer cursor has its hot spot at the upper left.
DeskTops
A desktop is a configuration of viewers as they are layed out on a screen. DeskTops.Create["name"] will create a new desktop named "name" if none exists. If one of that name exists, it will be moved onto the screen. DeskTops.FlyTo[desktop] will cause the contents of the screen to be saved in the current desktop, to be replaced by the viewers and icons in the new desktop.
EndOps
A boot file client may register a procedure which will be called synchronously after the Cedar boot sequence is completed, but before user input is enabled and any automatic checkpoint made.
HourGlass
This interface allows a client to display an hourglass cursor with flowing sand and is used during Cedar booting.
IconManager
This is a private interface that governs the behaviour of icons in response to selection and user type in.
Icons
The Icon interface exports a set of bitmap pictures used to display iconic viewers. A client may create new icons from either a bitmap or a procedure that makes use of Cedar Graphics to display the image. A client may specify a rectangle within an icon that will be labelled with the name of the particular iconic viewer by Viewers.
ImplErrors
A rudimentary debugger and signal catcher is exported by ImplErrors that gives the user the choice of rejecting, proceeding, or saving edits and rolling back when an error occurs. General use is not recommended.
InputFocus
InputFocus controls the destination of mouse and keyboard actions as well as the interpretation of these actions through TIP tables. A viewer class implementor would use this interface to acquire type-in or to inquire which viewer type-in was currently directed.
Labels
Labels implements a class of viewers that display a simple text message in a single font. The label may not be selected or edited, but has the advantage over Tioga text viewers of very low data structure overhead.
MBQueue
Some applications require a way to serialise user input from buttons, menus, and type-in without tying up the notifier process. MBQueue permits the application to enqueue and dequeue operations.
Menus
Menus are a horizontal sequence of text labels, each with an associated procedure called when the user clicks at the menu item. This interface provides low level routines for creating and modifying menus, but not for associating them with a particular viewer or redisplaying a viewer after its menu has changed.
MenusPrivate
A private interface enabling the window manager to invoke a menu item.
MessageWindow
The message window is a one-line display area at the top of the black and white display. Clients may use this interface to display prompts or other information to the user.
Rules
Rules are a simple viewer class that display as a rectangle of a single color on the display. They are useful for creating line graphics when designing the layout of tools.
TypeScript
This is a low-level interface that captures sequential type-in from the user. Clients are advised to use the IO streams interface instead.
VBootOps
A client may boot a particular volume or file with this interface.
VFonts
VFonts maps a font name into the actual representation, with options to synthesize bold and italic as well as to substitute for fonts that are not available.
ViewerAdjust
A private interface used to control user adjustment of viewer or column size and position.
ViewerBLT
A viewer class implementor may move displayed bits from one part of a viewer to another, with clipping to the viewer boundaries and almost the performance of the hardware BitBlt instruction. [This interface is not currently supported and should not be used].
ViewerEvents
ViewerEvents permits client procedures to be registered that will be called when certain events take place with respect to a viewer, such as save, new edits, open or close, move to a new column, and changes in the input focus.
ViewerMenus
A private interface containing most of the menu items found in the viewer caption menu.
ViewerClasses
ViewerClasses is an important interface that defines the viewer class and instance data structures, as well as many of the basic Viewers primitive types.
ViewerLocks
This interface provides read and write locking of viewers, columns and the entire viewer tree. [This interface is not currently supported and should not be used].
ViewerOps
ViewerOps is an important interface defining standard operations on viewers. Routines that manipulate viewer size and position, register new viewer classes, create new viewers, as well as most paint and input notifications live here.
ViewerSpecs
Screen layout constants are defined in the ViewerSpecs interface.
ViewersStallNotifier
Bugbane uses this private interface to notify Viewers when a process has been suspended, pending handling of a breakpoint of an uncaught signal.
ViewerTools
ViewerTools provides low level access to the contents of Tioga text viewers and permits clients to control selection and editing within them. See the ChoiceButtons interface for creating text prompt fields and other higher level user interface abstractions.
ViewersSnapshot
Client invoked Checkpoint and Rollback routines live here.
VirtualDesktops
This interface is being replaced by "DeskTops".
WindowManager
WindowManager contains a miscellaneous collection of routines, the most important being the ability to enable an additional column of viewers on a color display.
WindowManagerPrivate
This is a private interface containing the current viewer tree root and some input notification routines.