-- file: IntIdleLoop.mesa -- edited by Brotz, December 1, 1980 11:57 AM -- edited by Levin, 13-Nov-80 16:28:30 DIRECTORY DMSTimeDefs, dsD: FROM "DisplayDefs", Editor, inD: FROM "InteractorDefs", Inline, intCommon: FROM "IntCommon", ovD: FROM "OverviewDefs", ProcessDefs, tsD: FROM "TOCSelectionDefs", vmD: FROM "VirtualMgrDefs"; IntIdleLoop: MONITOR IMPORTS DMSTimeDefs, dsD, Editor, inD, intC: intCommon, Inline, ProcessDefs, tsD, vmD EXPORTS inD = PUBLIC BEGIN OPEN inD; -- Handles the IdleLoop and maintains the blinking caret. -- Global variables -- caretX: ScreenXCoord; caretY: ScreenYCoord; caretState: CaretState _ notVisible; caretLastUpdated: CARDINAL; nap: CONDITION; IdleLoop: PROCEDURE = -- Called by cursor tracking routines and any other routine that has time on its hands. -- Checks clock and calls procedures that must be activated at regular intervals, such as -- the time update for the top window and periodic mail checks. BEGIN DoTimeUpdate[]; -- Pause[]; ProcessDefs.Yield[]; UpdateDMandCMThumbLines[]; MaintainBlinkingCaret[]; END; -- of IdleLoop -- Pause: ENTRY PROCEDURE = INLINE -- causes the main Laurel process to give up control so that Pup and friends are happy. BEGIN WAIT nap; END; -- of IdleLoop -- DoTimeUpdate: PROCEDURE = INLINE -- Updates the date-time-of-day string, and posts it in the time of day house. BEGIN pt: DMSTimeDefs.PackedTime = GetPackedTime[]; elapsedSeconds: CARDINAL; IF intC.timeMayBeBogus THEN {intC.timeMayBeBogus _ FALSE; SetTime[]; RETURN}; IF pt.lowbits = intC.secondsLastChecked THEN RETURN; intC.secondsLastChecked _ pt.lowbits; elapsedSeconds _ intC.secondsLastChecked - intC.lastMinuteSeconds; IF elapsedSeconds < 60 THEN RETURN; intC.lastMinuteSeconds _ intC.lastMinuteSeconds + 60 * (elapsedSeconds / 60); DMSTimeDefs.MapPackedTimeToTimeZoneString[pt, intC.timeHouse.text]; TextHouseRefresher[intC.timeHouse]; END; -- of DoTimeUpdate -- -- GetPackedTime is copied from TimeConvert to minimize swapping GetPackedTime: PRIVATE PROCEDURE RETURNS [DMSTimeDefs.PackedTime] = BEGIN ht: DMSTimeDefs.HardwareTime _ DMSTimeDefs.currentTime^; RETURN[[num[highbits: ht.highbits, lowbits: ht.lowbits]]]; END; -- of GetPackedTime -- -- Thumb line updating procedures UpdateThumbLineRecord: TYPE = RECORD [region: {toc, displayed, composed}, tlnp: ThumbLineNbrPtr, exists: BOOLEAN, length, start, end, selection: CARDINAL]; UpdateTOCThumbLine: PROCEDURE = -- Checks the TOC thumb line for a change in state and updates accordingly. BEGIN tnp: TOCTextNbrPtr _ intC.tocTextNbr; updateThumbLineRecord: UpdateThumbLineRecord; updateThumbLineRecord _ UpdateThumbLineRecord [region: toc, tlnp: intC.tocThumbLineNbr, exists: intC.haveMailFile, length: IF intC.haveMailFile THEN vmD.GetFirstFreeTOCIndex[] - 1 ELSE 0, start: tnp.lines.linePair.index - 1, end: tnp.firstLineOffScreen.linePair.index - 1, selection: IF tsD.TOCSelectionEmpty[] THEN 0 ELSE tsD.FirstSelectedEntry[] - 1]; UpdateThumbLine[@updateThumbLineRecord]; END; -- of UpdateTOCThumbLine -- UpdateDMandCMThumbLines: PROCEDURE = -- Checks the DM and CM thumb lines for a change in state and updates accordingly. BEGIN updateThumbLineRecord: UpdateThumbLineRecord _ [region: displayed, tlnp: intC.dmThumbLineNbr, exists: , length: , start: , end: , selection: intC.target.start]; SetFromMNP: PROCEDURE[mnp: MessageTextNbrPtr] = BEGIN updateThumbLineRecord.start _ mnp.lines.firstCharIndex; updateThumbLineRecord.end _ mnp.firstLineOffScreen.firstCharIndex; updateThumbLineRecord.length _ IF (updateThumbLineRecord.exists _ mnp.haveMessage) THEN vmD.GetMessageSize[mnp.message] ELSE 0; END; -- of SetFrom MNP -- SetFromMNP[intC.dmTextNbr]; UpdateThumbLine[@updateThumbLineRecord]; updateThumbLineRecord.region _ composed; updateThumbLineRecord.tlnp _ intC.cmThumbLineNbr; SetFromMNP[intC.cmTextNbr]; UpdateThumbLine[@updateThumbLineRecord]; END; -- of UpdateDMandCMThumbLines -- UpdateThumbLine: PROCEDURE [utlr: POINTER TO UpdateThumbLineRecord] = -- Checks a thumb line for a change in state and updates accordingly. BEGIN OPEN utlr; quotient, remainder: CARDINAL; startX, endX, selectionX: ScreenXCoord; tlnp: ThumbLineNbrPtr _ utlr.tlnp; xRange: CARDINAL _ tlnp.rightX - tlnp.leftX; IF exists THEN BEGIN IF ~tlnp.exists OR tlnp.length # length OR tlnp.start # start OR tlnp.end # end OR (region # displayed AND tlnp.selection # selection) THEN BEGIN -- state changed and thumbable information exists tlnp.exists _ exists; tlnp.length _ length; tlnp.start _ start; tlnp.end _ end; tlnp.selection _ selection; IF length = 0 THEN BEGIN dsD.ClearRectangle[tlnp.leftX, tlnp.rightX, tlnp.topY + 1, tlnp.topY + 11]; dsD.BlackenRectangle[tlnp.leftX, tlnp.rightX, tlnp.topY + 5, tlnp.topY + 7]; tlnp.startX _ tlnp.leftX; tlnp.endX _ tlnp.leftX; tlnp.selectionX _ tlnp.leftX; END ELSE BEGIN [quotient, remainder] _ Inline.LongDivMod[Inline.LongMult[start, xRange], length]; startX _ quotient + tlnp.leftX + (IF remainder > 0 THEN 1 ELSE 0); [quotient, remainder] _ Inline.LongDivMod[Inline.LongMult[end, xRange], length]; endX _ quotient + tlnp.leftX + (IF remainder > 0 THEN 1 ELSE 0); IF region # displayed THEN BEGIN [quotient, remainder] _ Inline.LongDivMod[Inline.LongMult[selection, xRange], length]; selectionX _ quotient + tlnp.leftX + (IF remainder > 0 THEN 1 ELSE 0); END; IF startX + 8 > endX THEN BEGIN IF startX + 8 > tlnp.rightX THEN startX _ endX - 8 ELSE endX _ startX + 8; END; IF tlnp.startX # startX OR tlnp.endX # endX OR (region # displayed AND tlnp.selectionX # selectionX) THEN BEGIN OPEN dsD; IF region # displayed THEN PaintPicture[tlnp.selectionX, tlnp.topY+1, selectionThumbMark, erase]; ClearRectangle[tlnp.leftX, startX, tlnp.topY + 4, tlnp.topY + 8]; BlackenRectangle[tlnp.leftX, startX, tlnp.topY + 5, tlnp.topY + 7]; ReplaceRectangle[startX, endX, tlnp.topY + 4, tlnp.topY + 8, dottedLine]; ClearRectangle[endX, tlnp.rightX, tlnp.topY + 4, tlnp.topY + 8]; BlackenRectangle[endX, tlnp.rightX, tlnp.topY + 5, tlnp.topY + 7]; IF region # displayed THEN PaintPicture[selectionX, tlnp.topY + 1, selectionThumbMark, replace]; tlnp.startX _ startX; tlnp.endX _ endX; tlnp.selectionX _ selectionX; END; END; END; END ELSE IF tlnp.exists THEN BEGIN tlnp.exists _ FALSE; tlnp.startX _ tlnp.endX _ 0; dsD.ClearRectangle[tlnp.leftX, tlnp.rightX, tlnp.topY + 1, tlnp.topY + 11]; dsD.BlackenRectangle[tlnp.leftX, tlnp.rightX, tlnp.topY + 5, tlnp.topY + 7]; END; END; -- of UpdateThumbLine -- StartBlinkingCaret: PROCEDURE [x: ScreenXCoord, y: ScreenYCoord] = -- Notes time of call. Then places upper left corner of box containing caret at x,y. BEGIN StopBlinkingCaret[]; caretX _ x; caretY _ y; dsD.PaintPicture[caretX, caretY, caret, dsD.invert]; caretState _ black; caretLastUpdated _ realTimeClock^; END; -- of StartBlinkingCaret -- MaintainBlinkingCaret: PROCEDURE = -- Inverts caret at remembered x,y at appropriate time. BEGIN IF caretState = notVisible THEN RETURN; -- check if .3 seconds have elapsed since last caret inversion -- IF LOOPHOLE[realTimeClock^ - caretLastUpdated, CARDINAL] >= 9 THEN BEGIN -- one third second has elapsed since last update -- dsD.PaintPicture[caretX, caretY, caret, dsD.invert]; caretState _ IF caretState = black THEN white ELSE black; caretLastUpdated _ realTimeClock^; END; END; -- of MaintainBlinkingCaret -- StopBlinkingCaret: PROCEDURE = -- Restores caret picture to original state. BEGIN IF caretState = black THEN dsD.PaintPicture[caretX, caretY, caret, dsD.invert]; caretState _ notVisible; END; -- of StopBlinkingCaret -- SetCaretBlinking: PROCEDURE [charIndex: ovD.CharIndex, mnp: MessageTextNbrPtr] = BEGIN OPEN Editor; line: LinePtr; line _ MapCharIndexToLine[charIndex, mnp]; IF line # NIL THEN BEGIN caretX: ScreenXCoord _ MapCharIndexInLineToLeftX[charIndex, line, mnp.message] - 3; caretY: ScreenYCoord _ line.y + 9; StartBlinkingCaret[caretX, caretY]; END; END; -- of SetCaretBlinking -- -- Main body -- ProcessDefs.InitializeCondition[@nap, 1]; END. -- of IntIdleLoop -- (635)\f1