ui/src/vbt/VBTRep.i3


 Copyright (C) 1992, Digital Equipment Corporation                         
 All rights reserved.                                                      
 See the file COPYRIGHT for a full description.                            
                                                                           
 VBTRep.def, code Sun Aug 11 12:18:43 1985 by Greg Nelson 
 Last modified on Mon Dec 21 17:55:03 PST 1992 by msm     
      modified on Mon Feb 24 13:59:00 PST 1992 by muller  
      modified on Thu Jan 23 10:02:46 PST 1992 by gnelson 
      modified on Tue Jul 24 13:15:10 PDT 1990 by steveg 

<*PRAGMA LL*>
The VBTRep interface defines the representation of VBTs, and provides operations that are useful for implementing low-level or esoteric split classes.

INTERFACE VBTRep;

IMPORT Batch, Cursor, PropertyV, Rect, Region,
  ScreenType, ScrnPaintOp, ScrnCursor, ScrnPixmap,
  ScrnFont, VBT, VBTClass, Word, PaintPrivate, Axis, Palette,
  PaintOp, Font, Pixmap;

CONST EmptyCage = VBT.EmptyCage;

TYPE
  MiscRef = REF MiscRec;
  MiscRec = RECORD
    cage := EmptyCage;
    badRgn := Region.Empty;
    rpseqno: Word.T;
    oldDomain := Rect.Empty;
    link: MiscRef := NIL
  END;
To save space in a VBT, the cage, badRgn, rpseqno, and oldDomain fields are only stored if at least one of them has an ``unusual'' value. This is achieved by including a MiscRef in the VBT object. If the MiscRef is NIL, then the badRgn and oldDomain are empty, the rpseqno is irrelevant, and the cage is determined from the cagetype field as follows: if the cagetype is VBT.CageType.Rectangle, then the cage rectangle is assumed to be Rect.Empty; otherwise the rectangle is irrelevant.

The rpseqno field is the {\it repainting sequence number}. It is incremented whenever the badRgn is expanded and recorded before activating a repaint method. Thus when the repaint method returns, the current value can be compared with the recorded value to determine whether the current badRgn is the one that the repaint method responded to, or whether a new bad region arrived while the client was responding to the old one.

TYPE
  Prop =
    {EscapePending, Reshaping, RepaintPending, OnQ,
     Covered, Combiner, ShortCircuit, CageCovered,
     Marked, ExcessBegins, HasNewShape, BlockNewShape,
     EscapeCovered};
  Props = SET OF Prop;

CONST
  AllProps = Props{FIRST(Prop)..LAST(Prop)};
  NoProps = Props{};
Here is the meaning of the properties:

EscapePending: Set when a thread of control is forked to deliver a cage escape to gone. Set to FALSE when any position is delivered.

Reshaping: set when the VBT has a non-empty old domain.

RepaintPending: Set when a thread of control exists that will deliver the bad region.

OnQ: Set when the VBT is on the Metermaid's to-be-serviced queue.

Covered: Ordinarily painting into an empty batch will put the VBT on the Metermaid's queue and set onQ. If the covered bit is set, this will not happen. For example, PutPosition sets covered before passing the position to child, and clears it and forces the batch before it returns. Only set during event delivery, so any action that could be deferred until after event delivery can check covered and clean up on method exit.

Combiner: Set to indicate that this VBT is a good place to pile up small paint batches, even if it is not covered. Trestle sets this bit in one VBT near the root of a client address space to avoid shipping many small batches across RPC.

ShortCircuit: Set on a VBT when painting on the VBT can be implemented by clipping to the VBT's domain and painting on its parent.

Marked: set by VBT.Mark.

CageCovered: VBTClass.PutPosition sets this bit on a VBT before calling its position method; after calling the position method, the procedure relays the child's cage to the parent and clears the bit. VBTClass.SetCage notices the bit and omits relaying the cage to the parent.

ExcessBegins: Set when excessBegins > 0.

HasNewShape is set when VBT.NewShape is called, and cleared by a call to VBTClass.HasNewShape or VBTClass.GetShape.

If BlockNewShape is set, VBT.NewShape calls will not be relayed to the parent of the VBT.

REVEAL VBT.Prefix =
  VBTClass.Prefix BRANDED OBJECT
    <* LL >= {SELF} *>
    cursor := Cursor.DontCare;
    cageType: (*BITS 16 FOR*) VBTClass.VBTCageType
      := VBTClass.VBTCageType.Gone;
    props: (*BITS 16 FOR*) Props := NoProps;
    batch: Batch.T := NIL;
    remaining: INTEGER := 0;
    propset: PropertyV.Set := NIL;
    miscRef: MiscRef := NIL;
  OVERRIDES
    getcursor := GetcursorDefault;
    axisOrder := AxisOrderDefault;
  END;
The batch field contains the batch of uncompleted painting commands for the VBT, and remaining contains the number of free addressable units remaining in the batch. In particular, if remaining # 0, the batch field is not NIL. The miscRef field is always NIL if the parent is NIL.

REVEAL VBT.ScreenType <: STPub;

TYPE STPub =
  ScreenType.Public OBJECT
    ops: REF ARRAY OF ScrnPaintOp.T;
    cursors: REF ARRAY OF ScrnCursor.T;
    pixmaps: REF ARRAY OF ScrnPixmap.T;
    fonts: REF ARRAY OF ScrnFont.T
  METHODS
    opApply(cl: Palette.OpClosure; op: PaintOp.T): ScrnPaintOp.T;
    cursorApply(cl: Palette.CursorClosure; cs: Cursor.T): ScrnCursor.T;
    pixmapApply(cl: Palette.PixmapClosure; pm: Pixmap.T): ScrnPixmap.T;
    fontApply(cl: Palette.FontClosure; ft: Font.T): ScrnFont.T
  END;
The tables st.ops, st.fonts, st.cursors, and st.pixmaps are collectively called the screentype's {\it palette}. They are used to translate between screen-independent resources and screen-dependent resources. For example, recall that Pixmap.Gray is a record containing the integer field Pixmap.Gray.pm. The screen-dependent equivalent of Pixmap.Gray on the screentype st is simply st.pixmaps[Pixmap.Gray.pm]. When creating the palette, the above apply methods are called for all resources; if cl is NIL, the resource is built-in. The default values for these return the result of invoking the closure or the built-in method; your procedure must not return NIL when invoked on a built-in.

TYPE OffscreenType = VBT.ScreenType OBJECT st: VBT.ScreenType END;
An OffscreenType s, is a screen type that is derived from the screen type s.st. An OffscreenType will be replaced by its associated screentype in calls to Trestle.InstallOffscreen. The st field is read-only after creation.

PROCEDURE CheckMisc(v: VBT.T); <* LL >= {v} *>
Set v.misc := NIL if v's badRgn and oldDomain are empty and its cage type is not Rect.

PROCEDURE CreateMisc(v: VBT.T); <* LL >= {v} *>
If v.misc = NIL, then create a misc for v with empty badRgn and oldDomain, and with appropriate cage. Otherwise, do nothing.

PROCEDURE DestroyMisc(v: VBT.T);
<* LL >= {v, v.parent} *>
Set v's misc to NIL, clearing Reshaping from v.props.

PROCEDURE NewBatch(v: VBT.T; len: INTEGER := -1);
<* LL.sup = v *>
Force v's batch if it is non-nil and allocate a new batch for it of size at least len, or of size VBTTuning.BatchSize if len=-1.

PROCEDURE ForceBatch(v: VBT.T); <* LL.sup = v *>
Force v's batch if it is non-nil, and leave it nil.

PROCEDURE CancelBatch(v: VBT.T); <* LL.sup = v *>
Free v's batch and set it to NIL.

PROCEDURE Enqueue(v: VBT.T); <* LL.sup = v *>
Place v on the list of VBTs scheduled to be serviced by the MeterMaid.

PROCEDURE GetcursorDefault(v: VBT.Prefix): ScrnCursor.T;
Return the result of resolving cursor(v) using v's screentype.

PROCEDURE AxisOrderDefault(v: VBT.Prefix): Axis.T;
Return Axis.T.Hor.

PROCEDURE ExpandBadRect(w: VBT.T;
  READONLY clp: Rect.T; ba: Batch.T);
<* LL.sup = w *>
Expand w's bad region for ba.
 In ExpandBadRect, the rectangle clp is the original clipping
   rectangle for ba, before intersection with w.domain.  The
   expansion is caused by (a) using out-of-domain bits as source (b)
   painting into the old domain (c) scrolling an existing bad rectangle.
   

PROCEDURE ExtendBatch(v: VBT.T; VAR ba: Batch.T);
Extend v's batch to include the painting operations in ba, and free ba. It is assumed that v has a non-empty batch which has room for the extension.

PROCEDURE MaxRepeat(v: VBT.T): CARDINAL;
<* LL.sup = v *>
Return the number of RepeatRec's that can fit in v's current batch.

PROCEDURE PaintRepeat(v: VBT.T;
  READONLY clip: ARRAY OF Rect.T);
<* LL.sup = v *>
Add a RepeatRec to v's batch for each rectangle in clip.
 PaintRepeat is a checked run-time error if there isn't enough space
   in v's batch.  Calling PaintRepeat does not call
   Enqueue(v). 

PROCEDURE PaintSingle(v: VBT.T; READONLY clip: Rect.T;
  com: PaintPrivate.CommandPtr); <* LL.sup = v *>
Add the paint operation referenced by com to v's batch, but use the clipping rectangle clip instead of the one in com.
 PaintSingle forces v's batch if necessary and allocates a new
   one.  It does not call Enqueue(v).  The command com must not be a
   scroll command.  

PROCEDURE Scroll(v: VBT.T; READONLY clip: Rect.T;
  com: PaintPrivate.ScrollPtr); <* LL.sup = v *>
Like PaintSingle, but com must be a scroll command.

PROCEDURE Mark(v: VBT.T); <* LL >= {v} *>
Identical to VBT.Mark except for the locking level.

PROCEDURE Redisplay(); <* LL.sup = VBT.mu *>
Redisplay and unmark all marked windows whose screentype is non-NIL.
 That is, Redisplay is equivalent to this loop:

      LOOP
        WITH m = an array containing all marked windows DO
          IF NUMBER(m) = 0 THEN EXIT END;
          Sort m in order of non-decreasing depth;
          FOR i := 0 TO LAST(m) DO
            IF IsMarked(m[i]) AND m[i].st # NIL THEN
               Unmark(m[i]);
               m[i].redisplay()
            END
          END
        END
      END
The depth of a window is the number of parent pointers that must be followed to reach NIL. Sorting by depth guarantees that ancestors will be redisplayed before their descendants. The reason is that redisplaying an ancestor window often reshapes its descendants, and if a descendant is going to be reshaped it would be wasteful to redisplay it in its old position.

Ordinarily when a window is marked, a thread is forked that will call Redisplay. This is wasteful if Redisplay will be called soon anyway. Therefore, if you know that Redisplay will be called soon, you can call CoverRedisplay, which increments a ``coverage counter''. If the coverage counter is non-zero, marking a VBT does not fork a thread. Of course by calling CoverRedisplay you acquire the obligation to ensure that Redisplay will be called soon. Calling UncoverRedisplay decrements the counter and calls Redisplay if the result is zero.

PROCEDURE CoverRedisplay(); <* LL.sup = VBT.mu *>
Increment the redisplay coverage counter.

PROCEDURE UncoverRedisplay(); <* LL.sup = VBT.mu *>
Decrement the redisplay coverage counter and call Redisplay if the result is zero.

END VBTRep.