modified on Tue Aug 7 17:12:32 PDT 1990 by steveg
<*PRAGMA LL*>The
VBTClass
interface specifies the up methods, the split methods,
and the wrapper procedures by which a parent activates a child's down
methods.
In general, to implement a split or filter you override the down methods, up methods, and split methods of the parent. However, usually you will be able to inherit the majority of the methods from existing classes, and only have to override a few of them. We mention several groups of methods that in most cases you will want to inherit rather than reimplement.
The two down methods
VBT.Split.mouse VBT.Split.positiontogether with the two up methods
VBT.Split.setcage VBT.Split.setcursorconspire to implement the mouse-cage semantics described in the
VBT
interface for delivering mouse clicks and cursor positions and for
setting the cursor shape. They work for any VBT.Split
, and there is
almost never any reason to override them. As a far-fetched example of
when you would override them, imagine a filter that converts shifted
left button clicks to right button clicks.
Although you probably won't want to override these methods, you will
have to help them a bit. They cache the results of the locate
method,
and therefore require that you call VBTClass.LocateChanged
whenever
the geometry of your split changes in a way that affects the locate
method.
The up methods
VBT.Split.acquire VBT.Split.release VBT.Split.put VBT.Split.forge VBT.Split.readUp VBT.Split.writeUpimplement the event-time semantics described in the
VBT
interface.
They simply recurse up the tree of VBT
s. At the root the recursive
calls reach a VBT
in which these methods are overridden to make the
appropriate X calls. There is rarely any reason to override these
methods. As an example of when you might want to override them, imagine
keeping track of which VBT
in your application last held the keyboard
focus. You could do this by introducing a filter whose acquire
method
recorded the information before recursing on the parent.
Keystrokes and miscellaneous codes can skip levels of the tree when they are delivered. For example, associated with each top-level window is a filter much like the one just described, which keeps track of which of its decendants are selection owners. This filter forwards keystrokes and lost codes directly to the appropriate owner, bypassing the intermediate windows in the tree.
The up methods
VBT.Split.paintbatch VBT.Split.capture VBT.Split.syncimplement painting, painting synchronization, and screen capture. The
sync
and capture
methods recurse up the tree in the obvious way.
The paintbatch
method also recurses up the tree, but in a less obvious
way.
It would be too inefficient to call a method for every painting command;
therefore the class-independent painting code groups painting commands
into batches and hands them to the method a batch at a time. For
example, the paintbatch
method of a ZSplit
clips the batch of
painting commands to the visible portion of the child's domain and then
executes the clipped operations on itself.
Painting on the vast majority of VBT
s can be implemented simply by
clipping to their domain and then relaying the painting to their parent.
To speed up this common case, every VBT
has a {\it short-circuit} bit.
If this bit is set then Trestle doesn't call the VBT
's paintbatch
method at all; it just clips to the VBT
's domain and paints on its
parent. Typically the only VBT
s whose short-circuit bits are not set
are the root VBT
and those ZSplit
children that are overlapped by
other children or that extend outside the parent's domain.
If the short-circuit bits are set on all the VBT
s from v
to the
root, then the class-independent painting code will relay batches of
painting commands from v
to the root without activating any methods.
The paintbatch
method at the root translates the batch of painting
commands into the appropriate X operations.
The default method VBT.Split.paintbatch
sets the short-circuit bit and
recurses on the parent. In the unlikely event that you want to override
this method, the interfaces Batch
, BatchUtil
, and PaintPrivate
define the representation of painting commands in batches. You could
for example overriding the paintbatch method to implement a class of
VBT
that paints into a raw pixmap in your address space.
To speed up painting, Trestle does not rely on garbage collection for paintbatches: you must free them explicitly.
You almost never need to implement the split methods succ
, pred
,
move
, nth
, index
, and locate
; on the other hand you must be
careful to inherit them from the right place. There are two main
subtypes of VBT.Split
, filters and ``proper'' splits, and they have
different suites of split methods. The implementations of the split
methods for filters are
Filter.T.succ Filter.T.pred Filter.T.move Filter.T.nth Filter.T.index Filter.T.locateThese are all quite trivial procedures, since a filter has at most one child. If you declare a split as a subtype of
Filter.T
, you inherit
these methods automatically.
Most proper splits are subtypes of ProperSplit.T
, which keeps the
children in a doubly-linked list. For example, ZSplits
, HVSplits
,
TSplits
, and PackSplits
are all subtypes of ProperSplit.T
. The
methods
ProperSplit.T.succ ProperSplit.T.pred ProperSplit.T.move ProperSplit.T.nth ProperSplit.T.index ProperSplit.T.locateimplement the split methods using the doubly-linked list. If you declare a split as a subtype of
ProperSplit.T
, you inherit these
methods automatically.
INTERFACEBefore we get to the up methods and the split methods, there is more to be revealed aboutVBTClass ; IMPORT VBT, Trestle, Axis, Point, Rect, Region, ScrnCursor, ScrnPixmap, Cursor, Batch;
VBT
s in general:
REVEAL VBT.Prefix <: Prefix; TYPE Prefix = MUTEX OBJECT <* LL >= {VBT.mu, SELF} *> parent: VBT.Split := NIL; upRef : ROOT := NIL; domain: Rect.T := Rect.Empty; st : VBT.ScreenType := NIL; METHODS <* LL.sup = SELF *> getcursor (): ScrnCursor.T; <* LL.sup = VBT.mu *> axisOrder (): Axis.T; END;From
VBT.Prefix <: Prefix
it follows VBT.T <: Prefix
; hence every
VBT
is a MUTEX
object, and has the above fields and methods. The
complete revelation for the type VBT.T
is private to Trestle.
The fields v.parent
, v.domain
, and v.st
record v
's parent,
domain, and screentype.
The object v.upRef
is used by the methods of v.parent
to store
information specific to the child v
. For example, if v.parent
is a
ZSplit
, then v.upRef
contains a region representing the visible part
of v
, pointers to the children before and after v
, and other
information. In a filter, v.upRef
is usually NIL
, since when there
is only one child, all the state can be stored in data fields directly
in the parent object.
If v.parent
is NIL
, then so is v.upRef
.
The locking level comment on the data fields means that in order to
write one of the fields v.parent
, v.upRef
, v.domain
, or v.st
, a
thread must have both VBT.mu
and v
locked. Consequently, in order
to read one of the fields, a thread must have either VBT.mu
(or a
share of VBT.mu
) or v
locked. Thus the fields can be read either by
up methods or by down methods.
The call v.getcursor()
returns the cursor that should be displayed
over v
; that is, the cursor that was called GetCursor(v)
in the
VBT
interface. It is almost never necessary to override the
getcursor
method, since leaves and splits have suitable default
methods.
The axisOrder
method determines whether it is preferable to fix a
VBT
's height first or its width first. For example, a horizontal
packsplit would rather have its width fixed before its range of heights
is queried, since its height depends on its width. In general, if v
's
size range in axis ax
affects its size range in the other axis (and
not vice-versa), then v.axisOrder()
should return ax
. The default
is to return Axis.T.Hor
.
Next we come to the specifications of the split methods and the up methods:
REVEAL VBT.Split <: Public; TYPE Public = VBT.Leaf OBJECT METHODS (* | (* The split methods *) *) <* LL >= {VBT.mu, SELF, ch} *> beChild (ch: VBT.T); <* LL.sup = VBT.mu *> replace (ch, new: VBT.T); insert (pred, new: VBT.T); move (pred, ch: VBT.T); locate (READONLY pt: Point.T; VAR (*OUT*) r: Rect.T): VBT.T; <* LL >= {VBT.mu} *> succ (ch: VBT.T): VBT.T; pred (ch: VBT.T): VBT.T; nth (n: CARDINAL): VBT.T; index (ch: VBT.T): CARDINAL; (* | (* The up methods *) *) <* LL.sup = ch *> setcage (ch: VBT.T); setcursor (ch: VBT.T); paintbatch (ch: VBT.T; b: Batch.T); sync (ch: VBT.T; wait := TRUE); capture (ch: VBT.T; READONLY rect: Rect.T; VAR (*out*) br: Region.T): ScrnPixmap.T; screenOf (ch: VBT.T; READONLY pt: Point.T): Trestle.ScreenOfRec; <* LL.sup < SELF AND LL >= {ch, VBT.mu.ch} *> newShape (ch: VBT.T); <* LL.sup = ch *> acquire (ch: VBT.T; w: VBT.T; s: VBT.Selection; ts: VBT.TimeStamp) RAISES {VBT.Error}; release (ch: VBT.T; w: VBT.T; s: VBT.Selection); put ( ch : VBT.T; w : VBT.T; s : VBT.Selection; ts : VBT.TimeStamp; type : VBT.MiscCodeType; READONLY detail := VBT.NullDetail) RAISES {VBT.Error}; forge ( ch : VBT.T; w : VBT.T; type : VBT.MiscCodeType; READONLY detail := VBT.NullDetail) RAISES {VBT.Error}; <* LL.sup <= VBT.mu *> readUp (ch: VBT.T; w : VBT.T; s : VBT.Selection; ts: VBT.TimeStamp; tc: CARDINAL ): VBT.Value RAISES {VBT.Error}; writeUp (ch : VBT.T; w : VBT.T; s : VBT.Selection; ts : VBT.TimeStamp; val: VBT.Value; tc : CARDINAL ) RAISES {VBT.Error}; END;Notice that a
VBT.Split
is a subtype of a VBT.Leaf
. That is, every
VBT.Split
is also a VBT.Leaf
, and therefore the painting operations
in the VBT
interface can be applied to splits. This fact is revealed
here rather than in the VBT
interface to prevent clients of VBT
from
accidentally painting on splits. To do so is almost certainly a
mistake---it is the responsibility of the split's implementation to
paint on the parent as necessary to keep its screen up to date.
\subsubsection{Specifications of the split methods}
The first group of methods implement the behavior in the Split
interface:
The method call v.beChild(ch)
initializes ch.upRef
as appropriate
for a child of v
. The method can assume that ch
is non-nil and has
the same screentype as v
. When the method is called, LL >= {VBT.mu,
v, ch}
.
When declaring a subtype ST
of a split type S
, the beChild
method
for ST
will ordinarily call S.beChild(v, ch)
, which in turn will
call S
's supertype's beChild
method, and so on. Only one of the
methods should allocate the upRef
, but all of them may initialize
different parts of it. Two rules make this work. First, the type of
the upRef
for children of ST
splits should be a subtype of the type
of the upRef
for children of S
splits. Second, if a beChild
method finds ch.upRef
is NIL
and NIL
is not appropriate for the
type, the method should allocate ch.upRef
; otherwise it should narrow
ch.upRef
to the appropriate type and initialize it.
For example, HVSplit.T
is a subtype of ProperSplit.T
. Hidden in the
HVSplit
module is a type HVSplit.Child
, which represents the
per-child information needed by an HVSplit
. The type HVSplit.Child
is a subtype of ProperSplit.Child
. The method HVSplit.beChild(hv,
ch)
allocates a new HVSplit.Child
, stores it in ch.upRef
,
initializes the part of it that is specific to HVSplit
, and then calls
ProperSplit.beChild(hv, ch)
, which initializes the part of ch.upRef
that is common to all proper splits, and then calls its supertype's
beChild
method, and so on.
The chain of calls eventually ends with a call to VBT.Split.beChild
,
which causes an error if ch
is not detached or if ch
's screentype
differs from v
, and otherwise sets ch.parent
to v
and marks v
for redisplay.
The method call v.replace(ch, new)
simply implements the operation
Split.Replace(v, ch, new)
, and the call v.replace(ch, NIL)
implements Split.Delete(v, ch)
. Before calling the method, the
generic code in Split
marks v
for redisplay, checks that ch
is a
child of v
and that new
is detached, and rescreens new
to the
screentype of v
.
Similarly, the method call v.insert(pred, new)
implements the
operation Split.Insert(v, pred, new)
. Before calling the method, the
generic code in Split
marks v
for redisplay, checks that pred
is
NIL
or a child of v
and that new
is detached, and rescreens new
to the screentype of v
. A split that can only contain a limited
number of children may detach and discard the previous child to
implement insert
.
The call v.move(pred, ch)
implements Split.Move(v, pred, ch)
.
Before calling the method, the generic code verifies that pred
and
ch
are children of v
(or NIL
, in the case of pred
), and avoids
the call if pred = ch
or v.succ(pred) = ch
.
When the replace
, insert
, or move
method is called, LL.sup =
VBT.mu
. The default methods are equal to NIL
; so every split class
must arrange to override these methods, usually by inheriting them from
Filter
or from ProperSplit
.
The method calls v.succ(ch)
, v.pred(ch)
, v.nth(n)
, and
v.index(ch)
implement the corresponding operations in the Split
interface. In all cases, LL >= {VBT.mu}
.
The default method VBT.Split.succ
is NIL
; so every split class must
arrange to override the method, usually by inheriting them from Filter
or from ProperSplit
. The default methods VBT.Split.pred
,
VBT.Split.nth
, and VBT.Split.index
are implemented by repeatedly
calling the succ
method.
The method call v.locate(pt, r)
returns the child of v
that controls
the position pt
, or NIL
if there is no such child. The method also
sets r
to a rectangle containing pt
such that for all points q
in
the meet of r
and domain(v)
, v.locate(q, ...)
would return the
same result as v.locate(pt, ...)
. The split implementation is
expected to make r
as large as possible, so that clients can avoid
calling locate
unnecessarily. When the method is called, pt
will be
in domain(v)
. When the locate method is called, LL.sup = VBT.mu
.
If v
inherits the mouse
, position
, setcursor
, or setcage
methods from VBT.Split
, then you must call LocateChanged(v)
whenever
any operation on the split invalidates a rectangle-child pair returned
previously by v.locate
:
PROCEDURE LocateChanged (v: VBT.Split); <* LL.sup = VBT.mu *>
Clear any cached results of the locate
method.
The default method
VBT.Split.locate(v, pt, r)
enumerates v
's
children in succ
order and returns the first child ch
whose domain
contains pt
. It sets r
to a maximal rectangle that lies inside the
domain of ch
and outside the domains of all preceding children. If no
child contains pt
, it returns NIL
and sets r
to a maximal
rectangle that lies inside the domain of v
and outside the domains of
all its children. This is suitable if the children don't overlap or if
whenever two children overlap, the top one appears earlier in succ
order.
\subsubsection{Specifications of the up methods}
So much for the split methods; here now are the specifications of the up
methods. In all cases, ch
is a child of v
.
The method call v.setcage(ch)
is called by the system whenever ch
's
cage is changed. It is called with LL.sup = ch
. The default method
implements the behavior described in the VBT
interface.
The method call v.setcursor(ch)
is called by the system whenever the
result of ch.getcursor()
might have changed. It is called with
LL.sup = ch
. The default method implements the behavior described in
the VBT
interface.
The method call v.paintbatch(ch, b)
is called to paint the batch b
of painting commands on v
's child ch
. The procedure can assume that
the batch is not empty and that its clipping rectangle is a subset of
ch
's domain. It is responsible for ensuring that b
is eventually
freed, which can be achieved by calling passing b
to Batch.Free
or
by passing b
to another paintbatch method, which will inherit the
obligation to free the batch. A paintbatch
method is allowed to
modify the batch. The default method clips the batch to ch
's domain,
paints the batch on the parent, and sets ch
's shortcircuit bit. The
method is called with LL.sup = ch
.
The method call v.sync(ch, wait)
implements VBT.Sync(ch, wait)
.
When the method is called, ch
's batch will have been forced. The
default method acquires v
, releases ch
, forces v
, calls
v.parent
's sync method, releases v
, and reacquires ch
. When the
method is called, ch
's batch is NIL
and LL.sup = ch
.
The method call v.capture(ch, r, br)
implements VBT.Capture(ch, r,
br)
. The default method recurses on the parent. When the method is
called, ch
's batch is NIL
, r
is a subset of ch
's domain, and
LL.sup = ch
.
The method call v.screenOf(ch, pt)
implements Trestle.ScreenOf(ch,
pt)
. The default method recurses on the parent. When the method is
called, LL.sup = ch
.
The method call v.newShape(ch)
signals that ch
's size range,
preferred size, or axis order may have changed. The default recurses on
the parent. When the method is called, LL.sup < v AND LL >= {ch,
VBT.mu.ch}
.
The remaining methods implement event-time operations for a descendent
(not necessarily a direct child) of the window v
. In all cases, ch
is a child of v
and w
is a descendant of ch
.
The acquire
, release
, put
, and forge
methods implement the
corresponding procedures from the VBT
interface. For example,
v.put(ch, w, s, ts, cd)
implements VBT.Put(w, s, ts, cd.type,
cd.detail)
. When these methods are called, LL.sup = ch
.
Similarly, the readUp
and writeUp
methods implement the procedures
VBT.Read
and VBT.Write
. When these methods are called, LL.sup <=
VBT.mu
.
\subsubsection{Getting and setting the state of a VBT}
PROCEDURE Cage (v: VBT.T): VBT.Cage; <* LL >= {v} *>
Return v's cage.
TYPE VBTCageType = {Gone, Everywhere, Rectangle}; PROCEDURE CageType (v: VBT.T): VBTCageType; <* LL >= {v} *>
Return v
's cage's type.
CageType(v)
returns Gone
if Cage(v) = VBT.GoneCage
, Everywhere
if Cage(v) = VBT.EverywhereCage
, and Rectangle
otherwise. It is
more efficient than Cage
.
PROCEDURE GetCursor (v: VBT.T): Cursor.T; <* LL >= {v} *>
Return cursor(v)
.
PROCEDURE SetShortCircuit (v: VBT.T); <* LL >= {v} *>
Set the short-circuit property of v
.
PROCEDURE ClearShortCircuit (v: VBT.T); <* LL >= {v} *>
Clear the short-ciruit propery of v
.
If
v
's short-circuit property is on, painting on v
will be
implemented by clipping to its domain and painting on its parent.
The next three procedures are equivalent to the corresponding procedures
in VBT
, except they have a different locking level:
PROCEDURE PutProp (v: VBT.T; ref: REFANY); <* LL >= {v} *> PROCEDURE GetProp (v: VBT.T; tc: INTEGER): REFANY; <* LL >= {v} *> PROCEDURE RemProp (v: VBT.T; tc: INTEGER); <* LL >= {v} *>In implementing a split it is sometimes necessary to read a child's bad region; in which case the following procedure is useful:
PROCEDURE GetBadRegion (v: VBT.T): Region.T; <* LL >= {v} *>
Return v's bad region; that is, the join ofbad(v)
andexposed(v)
.
For the convenience of split implementors, every
VBT
has a
``newshape'' bit which is set by a call to VBT.NewShape
. For example,
the redisplay or shape method of a split can test these bits to
determine which of its children have new shapes.
PROCEDURE HasNewShape (v: VBT.T): BOOLEAN; <* LL.sup < v *>
Return the value of v
's newshape bit.
PROCEDURE ClearNewShape (v: VBT.T); <* LL.sup < v *>
Clearv
'snewshape
bit.
\subsubsection{Procedures for activating the down methods of a VBT}
PROCEDURE Reshape (v: VBT.T; READONLY new, saved: Rect.T); <* LL.sup >= VBT.mu.v AND LL.sup <= VBT.mu *>
Prepare for and callv
'sreshape
method.
That is,
Reshape
changes v.domain
and then schedules a call to
v.reshape(VBT.ReshapeRec{v.domain, new, saved})It should always be called instead of a direct call to the method, since it establishes essential internal invariants before calling the method. The bits in the
saved
argument must remain valid until the method
returns. It is all right for saved
to be larger than v
's old
domain; Reshape
will clip it to v
's old domain before calling the
method. It is illegal to reshape a detached VBT
to have a non-empty
domain.
For example, the reshape
method of BorderedVBT
uses
VBTClass.Reshape
to reshape its child.
PROCEDURE Rescreen (v: VBT.T; st: VBT.ScreenType); <* LL.sup >= VBT.mu.v AND LL.sup <= VBT.mu *>
Prepare for and callv
'srescreen
method.
That is,
Rescreen
executes
prev := v.domain; v.domain := Rect.Empty; v.st := st; v.rescreen(VBT.RescreenRec{prev, st}).For example, to determine how large a menu
m
would be if it were
inserted into a ZSplit
z
, you can't simply call GetShapes(m)
,
since in general the screentype of m
could be different from the
screentype of z
, and the shape can depend on the screentype. But you
can call VBTClass.Rescreen(m, z.st)
followed by GetShapes(m)
.
PROCEDURE Repaint (v: VBT.T; READONLY badR: Region.T); <* LL.sup >= VBT.mu.v AND LL.sup <= VBT.mu *>
JoinbadR
intov
's bad region and then prepare for and callv
's repaint method.
PROCEDURE Position (v: VBT.T; READONLY cd: VBT.PositionRec); <* LL.sup = VBT.mu *>
Prepare for and callv
'sposition
method.
PROCEDURE Key (v: VBT.T; READONLY cd: VBT.KeyRec); <* LL.sup = VBT.mu *>
Prepare for and callv
'skey
method.
PROCEDURE Mouse (v: VBT.T; READONLY cd: VBT.MouseRec); <* LL.sup = VBT.mu *>
Prepare for and callv
'smouse
method.
PROCEDURE Misc (v: VBT.T; READONLY cd: VBT.MiscRec); <* LL.sup = VBT.mu *>
Prepare for and callv
'smisc
method.
The following two procedures schedule calls to the down methods without making the calls synchronously. They are useful when you hold too many locks to call a down method directly. For example, when a
ZSplit
child scrolls bits that are obscured, the locking level of the
paintbatch
method precludes calling the repaint
method directly; but
a call can be scheduled with ForceRepaint
.
PROCEDURE ForceEscape (v: VBT.T); <* LL.sup >= {v} *>
Enqueue a cage escape togone
for delivery tov
.
PROCEDURE ForceRepaint (v: VBT.T; READONLY rgn: Region.T; deliver := TRUE); <* LL.sup >= {v} *>
Joinrgn
intov
's bad region, and possibly schedule a call tov
's repaint method.
VBTClass.ForceRepaint
is like VBT.ForceRepaint
, except that it has a
different locking level, and if deliver
is FALSE
then no thread will
be forked to deliver the bad region---in this case the caller has the
obligation to deliver the bad region soon, either by calling
ForceRepaint
with deliver = TRUE
, or by calling Repaint
.
PROCEDURE Redisplay (v: VBT.T); <* LL.sup = VBT.mu *>
Ifv
is marked for redisplay, then unmark it and prepare for and callv.redisplay()
.
PROCEDURE GetShape (v : VBT.T; ax : Axis.T; n : CARDINAL; clearNewShape := TRUE): VBT.SizeRange; <* LL.sup >= VBT.mu.v AND LL.sup <= VBT.mu *>
Prepare for and callv
'sshape
method.
GetShape
causes a checked runtime error if the result of the shape
method is invalid. If clearNewShape
is TRUE
, GetShape
calls
ClearNewShape(v)
before it calls the method.
PROCEDURE GetShapes (v: VBT.T; clearNewShape := TRUE): ARRAY Axis.T OF VBT.SizeRange; <* LL.sup >= VBT.mu.v AND LL.sup <= VBT.mu *>
Return the shapes of v
in both axes.
GetShapes
calls the shape method of v
in each axis, using the order
determined by v.axisOrder()
, and returns the array of the resulting
size ranges. If clearNewShape
is TRUE
, GetShapes
calls
ClearNewShape(v)
before it calls the method.
GetShapes
is convenient if both the height and width preferences of
the child can be accomodated---for example, when inserting a top level
window or ZSplit
child.
PROCEDURE Detach (v: VBT.T); <* LL.sup = VBT.mu *>
Setv.parent
andv.upRef
toNIL
; setv
's domain to empty, enqueue a reshape to empty, and clearv
's shortcircuit bit.
\subsubsection{Procedures for activating the up methods of a VBT}
The following six procedures are like the corresponding procedures in
the VBT
interface, except that they have a different locking level:
PROCEDURE SetCage (v: VBT.T; READONLY cg: VBT.Cage); <* LL.sup = v *> PROCEDURE SetCursor (v: VBT.T; cs: Cursor.T); <* LL.sup = v *> PROCEDURE Acquire (v: VBT.T; s: VBT.Selection; t: VBT.TimeStamp) RAISES {VBT.Error}; <* LL.sup = v *> PROCEDURE Release (v: VBT.T; s: VBT.Selection); <* LL.sup = v *> PROCEDURE Put ( v : VBT.T; s : VBT.Selection; t : VBT.TimeStamp; type : VBT.MiscCodeType; READONLY detail := VBT.NullDetail) RAISES {VBT.Error}; <* LL.sup = v *> PROCEDURE Forge ( v : VBT.T; type : VBT.MiscCodeType; READONLY detail := VBT.NullDetail) RAISES {VBT.Error}; <* LL.sup = v *>Finally, here is a procedure for executing a batch of painting commands on a
VBT
:
PROCEDURE PaintBatch (v: VBT.T; VAR b: Batch.T); <* LL.sup < v *>
Execute the batchb
of painting commands onv
, freeb
, and setb
toNIL
.
The interpretation of
b
is described in the Batch
and PaintPrivate
interfaces. If b.clipped
is erroneously set to TRUE
, then
PaintBatch
may execute the batched painting commands without clipping
them to b.clip
, but it will not paint outside v
's domain.
END VBTClass.