// DKS.bcpl -- Display and Keyboard Support
// Copyright Xerox Corporation 1979, 1983
// Last modified January 8, 1983 3:50 PM by Boggs
get "AltoDefs.d"
get "SysDefs.d"
get "Disks.d"
get "Streams.d"
get "AltoFileSys.d"
get "Time.d"
get "ComStruct.bcpl"
static
[ ScrollResult
UserLineCheckpoint
UserBitCheckpoint
UserLines = defaultUserLines // size of display
UserLineEnds // vector 0..UserLines-1 of endpoints
BoldFont = 0
RegularFont = 0
PreTimeDcb
ScrollsSinceOK
ShouldSetTime
ShowTime
TimeOutCommand = 0
TIMESTR1
TIMESTR2
USERSTR
]
manifest
[ DisplayHead = #420
]
let WriteSys(C) be
[ WriteChars(C, 0, dsp)
]
and WRITE(C, BreakBetweenPages; numargs na) = valof
[ if na ls 2 then BreakBetweenPages = false
unless BreakBetweenPages do ScrollsSinceOK = 0
resultis WriteChars(C, 0, USERSTR)
]
and RESETPAGE(S) be
[ ScrollsSinceOK = 0
]
and WriteChars(C, RTN, Stream) = valof
[ ScrollResult = 0
test (C ge 0) & (C le #377)
ifso test RTN eq 0
ifso [ Puts(Stream, C & #177)
resultis ScrollResult
]
ifnot resultis RTN(C & #177) // MASK TO 7 BITS
ifnot [ let L = C>>STRING.length
let T = 0
let I = 1
while (T eq 0) & (I le L) do
[
let char = C>>STRING.char↑I
switchon char into
[
case #300: [ Bold(Stream); endcase ]
case #301: [ UnBold(Stream); endcase ]
default: T = WriteChars(char, RTN, Stream)
]
I = I+1
]
resultis T
]
]
and PRETTYWRITE(C) = valof
[ let BlankWidth = CharWidth(USERSTR, $*S)
let ColWidth = 10*BlankWidth
let CurPos = GetBitPos(USERSTR)
let NewPos = ((CurPos+3*BlankWidth)/ColWidth+1)*ColWidth
let CWidth = BitWidth(USERSTR, C)
test CWidth+NewPos ge GetRmarg(USERSTR)
ifnot SetBitPos(USERSTR, NewPos)
ifso [ let Result = WRITE($*N, true)
if Result ne 0 then resultis Result
]
resultis WRITE(C, true)
]
and CanOverlay() = valof
[
static [ free ]
let Check(od) be
unless ReleaseOverlay(od, true) do free = false
free = true
LockPendingCode()
GeneratePresentOverlays(Check)
resultis free
]
and TwiddleThumbs(TimeOutQ) be
[ manifest
[ // 20 minutes is 1,200,000 1 ms ticks
TwentyMinHi = 18 // x/65536
TwentyMinLo = 20352 // x mod 65536
// 1 minutes is 120,000 1 ms ticks
OneMin = 165140b // 60000d
]
let SortTimer = vec 1
let IdleTimer = vec 1
let CursorTimer = vec 1
let SpinDownTimer = vec 1
let PassNumber = 0
SETUPCLK(SpinDownTimer, 1000) // 1 sec
SETUPCLK(SortTimer, OneMin)
SETUPCLK(IdleTimer, TwentyMinLo, TwentyMinHi)
let LineDelta = GetLinePos(USERSTR)-UserLineCheckpoint
let BitPos = GetBitPos(USERSTR)
Puts(USERSTR, $*S)
while Endofs(keys) do
[ if TIMEHASCOME(SpinDownTimer) &
(@DiskStatus & #40) ne 0 then
EtherBoot(0)
SETUPCLK(CursorTimer, 500) // 1/2 second
RemoveCursor(UserLineCheckpoint+LineDelta,
BitPos)
PassNumber = PassNumber+1
Puts(USERSTR, (((PassNumber&1) eq 0)? $*S, $|))
if (@DiskStatus & #40) eq 0 then // Disk ready
[
if ShouldSetTime & DIRSTATE eq PAGESCOUNTED &
CanOverlay() then
[
ShouldSetTime = false
SetTime()
SETUPCLK(CursorTimer, 500) // 1/2 second
SETUPCLK(SortTimer, OneMin)
SETUPCLK(IdleTimer, TwentyMinLo, TwentyMinHi)
]
SETUPCLK(SpinDownTimer, 1000) // 1 sec
INITDIRBLK(true) // GET DIRECTORY INTO CORE
if directoryOutOfSort & TIMEHASCOME(SortTimer) &
CanOverlay() then
[
directoryOutOfSort = false
WriteSortedDirectory()
]
if TimeOutQ ne 0 & TIMEHASCOME(IdleTimer) then
[
WriteSortedDirectory()
if TimeOutCommand eq 0 then DIAGNOSE()
STRINGTOQR(TimeOutCommand, TimeOutQ)
PUTQR(TimeOutQ, $*n)
break
]
]
let tlc = 0
until TIMEHASCOME(CursorTimer) % (not Endofs(keys)) do
[
if (tlc&7) eq 0 then MAKETIMELINE()
tlc = tlc + 1
]
]
RemoveCursor(UserLineCheckpoint+LineDelta,
BitPos)
]
and RemoveCursor(BLine, BBitPos) be
[ let CurLine = GetLinePos(USERSTR)
while CurLine gr BLine do
[ ResetLine(USERSTR)
CurLine = CurLine-1
SetLinePos(USERSTR, CurLine)
]
SetBitPos(USERSTR, BBitPos)
EraseBits(USERSTR, GetRmarg(USERSTR)-BBitPos)
SetBitPos(USERSTR, BBitPos)
]
and FlashScreen() be
[
let invert() be
[
let dcb = @DisplayHead
until dcb eq 0 do
[ dcb>>DCB.background = dcb>>DCB.background xor 1
dcb = dcb>>DCB.next
]
]
invert()
let FlashTimer = vec 2
SETUPCLK(FlashTimer, 250) // 1/4 second
let dummy = 250
until TIMEHASCOME(FlashTimer) do [ dummy = dummy*dummy ]
invert()
]
and Bold(Stream) be
[
if RegularFont eq 0 then SetUpBold(Stream)
SetFont(Stream, BoldFont)
]
and UnBold(Stream) be
[
if RegularFont eq 0 then SetUpBold(Stream)
SetFont(Stream, RegularFont)
]
and SetUpBold(Stream) be
[
RegularFont = GetFont(Stream)
BoldFont = Allocate(CZ,2)+2
BoldFont!-2 = -1
BoldFont!-1 = RegularFont
]
and InitUserLine(Prompt) be
[ WRITE($*N)
WRITE(Prompt)
UserLineCheckpoint = GetLinePos(USERSTR)
UserBitCheckpoint = GetBitPos(USERSTR)
]
and FitsThisLine(S, C, Extra; numargs na) = valof
[ resultis (GetRmarg(S) gr
(GetBitPos(S)+BitWidth(S, C)+
((na ge 3)? Extra, 0)))
]
and BitWidth(S, C) = valof
[ if (C le 0) % (C ge #377) then
[ let Sum = 0
for i=1 to C>>STRING.length do
Sum = Sum+CharWidth(S, C>>STRING.char↑i)
resultis Sum
]
resultis CharWidth(S, C)
]
and UserScroll(ds, char; numargs na) = valof
[ if na ls 2 then resultis DefaultScroll(ds)
switchon char into
[
case $*N: endcase
case #11: // tab
resultis DefaultScroll(ds, char)
case $*L: case 0: // null, lf
resultis char
case -1: // about to burp lines up one
resultis TestScrollCount(ds)
case -2: // about to lose data off top of screen
resultis char
default:
[
test char ls #40
ifso [ Puts(ds, $↑); Puts(ds, char+#100) ]
ifnot endcase
resultis char
]
]
let curBit = GetBitPos(ds)
let rpos = CharWidth(ds, char) + curBit
if rpos le GetRmarg(ds) then // char really fits
resultis DefaultScroll(ds, char)
let curLine = GetLinePos(ds)
UserLineEnds!curLine = curBit
unless SetLinePos(ds, curLine+1) do
resultis DefaultScroll(ds, char)
SetBitPos(ds, GetLmarg(ds))
if char ne $*N then Puts(ds, char)
resultis char
]
and TestScrollCount(ds) = valof
[
if ScrollsSinceOK ge UserLines-1 then
[ ScrollsSinceOK = 0
if LASTONEINKEYS(CONTROLC) ne 0 then
[ ScrollResult = CONTROLC
resultis false
]
Wss(ds, "*NMore?")
Resets(keys)
while Endofs(keys) do
INITDIRBLK(true)
if LASTONEINKEYS(CONTROLC) ne 0 then
[ ScrollResult = CONTROLC
resultis false
]
let c = Gets(keys)
Puts(ds,$*n)
switchon c into
[ case $N:
case $n:
case #177:
ScrollResult = Capitalize(c)
resultis false
default:
]
while FitsThisLine(ds, $~) do Puts(ds, $~)
ScrollsSinceOK = 0
]
for i = 0 to UserLines-1 do
UserLineEnds!i = UserLineEnds!(i+1)
UserLineCheckpoint = UserLineCheckpoint-1
ScrollsSinceOK = ScrollsSinceOK+1
resultis true
]
and OverType(Q, PROMPT) be
[ if UserLineCheckpoint ls 0 then
[ RETYPE(Q, WRITE, PROMPT)
return
]
let CurLinePos = GetLinePos(USERSTR)
let CurBitPos = GetBitPos(USERSTR)
SetLinePos(USERSTR, UserLineCheckpoint)
SetBitPos(USERSTR, UserBitCheckpoint)
let SavedULC = UserLineCheckpoint
MapQ(Q, WRITE) // This may decrement UserLineCheckpoint
UserLineCheckpoint = SavedULC
let NewLinePos = GetLinePos(USERSTR)
let NewBitPos = GetBitPos(USERSTR)
EraseBits(USERSTR, GetRmarg(USERSTR)-NewBitPos)
while NewLinePos ls CurLinePos do
[ SetLinePos(USERSTR, CurLinePos)
ResetLine(USERSTR)
CurLinePos = CurLinePos-1
]
SetBitPos(USERSTR, NewBitPos)
SetLinePos(USERSTR, NewLinePos)
]
and EraseChar(c) = valof
[
if c ls #40 then
[
if c eq $*T % c eq $*N then resultis false
if c eq $*L % c eq 0 then resultis true
test EraseChar(c+#100)
ifso resultis EraseChar($↑)
ifnot resultis false
]
let width = CharWidth(USERSTR, c)
if GetBitPos(USERSTR)-width ge GetLmarg(USERSTR) then
[ // on this line
EraseBits(USERSTR, -width)
resultis true
]
let curLine = GetLinePos(USERSTR)
if curLine eq 0 resultis false
ResetLine(USERSTR)
curLine = curLine-1
SetLinePos(USERSTR, curLine)
SetBitPos(USERSTR, UserLineEnds!curLine)
resultis EraseChar(c)
]
and RETYPE(TOQ, WriteFn, PROMPT) be
[ if PROMPT eq 0 then return
test WriteFn eq WRITE
ifso
test UserLineCheckpoint ge 0
ifso
[
let curLine = GetLinePos(USERSTR)
until curLine eq UserLineCheckpoint do
[
ResetLine(USERSTR)
curLine = curLine-1
SetLinePos(USERSTR, curLine)
]
SetBitPos(USERSTR, UserBitCheckpoint)
EraseBits(USERSTR,
GetRmarg(USERSTR)-UserBitCheckpoint)
SetBitPos(USERSTR, UserBitCheckpoint)
]
ifnot InitUserLine(PROMPT)
ifnot
[ WriteFn($*N)
WriteFn(PROMPT)
]
MapQ(TOQ, WriteFn)
]
and MapQ(Q, Fn) be
[ let MYQ = vec size QS/16
INITQ(MYQ)
until ISEMPTYQ(Q) do
[ let C = GETQF(Q)
Fn(C)
PUTQR(MYQ, C)
]
APPENDQ(Q, MYQ, Q)
]
and LOOKFORCTLC() = valof
[ let CharNoOfLastCtlC = LASTONEINKEYS(CONTROLC)
if CharNoOfLastCtlC ne 0 then
[ for I=1 to CharNoOfLastCtlC-1 do Gets(keys)
resultis true
]
resultis false
]
and LASTONEINKEYS(char) = valof
[ let CurrentCharNo = 1
let CharNoOfLastGoodie = 0
let NextOut = OsBuffer>>OsBUF.Out
if NextOut eq OsBuffer>>OsBUF.Last then
NextOut = OsBuffer>>OsBUF.First
while NextOut ne OsBuffer>>OsBUF.In do
[ if @NextOut eq char then
CharNoOfLastGoodie = CurrentCharNo
CurrentCharNo = CurrentCharNo+1
NextOut = NextOut+1
if NextOut eq OsBuffer>>OsBUF.Last then
NextOut = OsBuffer>>OsBUF.First
]
resultis CharNoOfLastGoodie
]
and CatchBlankKeys(kbTable) = valof
[ if kbTable>>KBTRANS.Transition ge 0 then resultis true
let char = nil
switchon kbTable>>KBTRANS.Transition & 377b into
[
case 30: // spare2
[ char = 202b; endcase ]
case 31: // spare1
[ char = 201b; endcase ]
case 61: // spare3
[ char = 203b; endcase ]
default: resultis true
]
let newIn = OsBuffer>>OsBUF.In + 1
if newIn eq OsBuffer>>OsBUF.Last then
newIn = OsBuffer>>OsBUF.First
if newIn ne OsBuffer>>OsBUF.Out then
[
@(OsBuffer>>OsBUF.In) = char
OsBuffer>>OsBUF.In = newIn
]
resultis false
]
and MAKETIMELINE() be
[
ShowTime = ShowTime eq TIMESTR1? TIMESTR2, TIMESTR1
WriteChars(FORMATN("*n-- <S> ",ExecRelease), 0, ShowTime)
let TIME = vec lenUTV
UNPACKDT(0, TIME)
let MESSAGE = vec 100
test (TIME>>UTV.year ls 1983) % (TIME>>UTV.year gr 1990)
ifso FORMAT(MESSAGE, " Date and Time Unknown - <D> Pages --",
sysDisk>>DSK.diskKd>>KDH.freePages)
ifnot
[
FORMAT(MESSAGE, " <S>day <S> <D> - <D>:<D 2 $0>:<D 2 $0> <S> - <D> Pages --",
selecton TIME>>UTV.weekday into
[ case 0: "Mon"
case 1: "Tues"
case 2: "Wednes"
case 3: "Thurs"
case 4: "Fri"
case 5: "Satur"
case 6: "Sun"
],
selecton TIME>>UTV.month into
[ case 0: "Jan"
case 1: "Feb"
case 2: "Mar"
case 3: "Apr"
case 4: "May"
case 5: "Jun"
case 6: "Jul"
case 7: "Aug"
case 8: "Sep"
case 9: "Oct"
case 10: "Nov"
case 11: "Dec"
],
TIME>>UTV.day,
valof
[ let HOUR = TIME>>UTV.hour
if HOUR ge 12 then HOUR = HOUR-12
if HOUR eq 0 then HOUR = 12
resultis HOUR
],
TIME>>UTV.minute,
TIME>>UTV.second,
((TIME>>UTV.hour ls 12)? "am", "pm"),
sysDisk>>DSK.diskKd>>KDH.freePages)
]
let MSGWidth = BitWidth(ShowTime, MESSAGE)
while FitsThisLine(ShowTime, $-, MSGWidth) do
Puts(ShowTime, $-)
Wss(ShowTime, MESSAGE)
PreTimeDcb>>DCB.next = ShowTime>>DS.fdcb
]