DIRECTORY Atom, CD, CDBasics, CDBasicsInline, CDCells, CDDirectory, CDDrawQueue, CDEvents, CDInstances, CDImports, CDIO, CDOps, CDOpsExtras, CDPrivate, CDProperties, CDSequencer, CDValue, Convert, IO, Process, RefTab, Rope, SafeStorage, SymTab, RuntimeError USING [UNCAUGHT], TerminalIO, UserProfile; CDOpsImpl: CEDAR MONITOR IMPORTS Atom, CD, CDBasics, CDBasicsInline, CDCells, CDDirectory, CDDrawQueue, CDEvents, CDInstances, CDIO, CDOps, CDPrivate, CDProperties, CDValue, Convert, IO, Process, RefTab, Rope, RuntimeError, SafeStorage, SymTab, TerminalIO, UserProfile EXPORTS CDOps, CDOpsExtras SHARES CD = BEGIN createEvent: CDEvents.EventRegistration=CDEvents.RegisterEventType[$CreateNewDesign]; resetDesignEvent: CDEvents.EventRegistration=CDEvents.RegisterEventType[$ResetDesign]; renameEvent: CDEvents.EventRegistration _ CDEvents.RegisterEventType[$RenameDesign]; beforeRenameEvent: CDEvents.EventRegistration _ CDEvents.RegisterEventType[$BeforeRenameDesign]; DrawDesc: TYPE = RECORD [area: CD.Rect, clear: BOOL]; DelayedRedrawRec: TYPE = RECORD [ delayedList: LIST OF DrawDesc_NIL, length: INT _ 0 ]; GetDelayedRedrawRef: PROC [design: CD.Design] RETURNS [REF DelayedRedrawRec] = { WITH design.delayedRedrawsPriv SELECT FROM dr: REF DelayedRedrawRec => RETURN [dr]; ENDCASE => { dr: REF DelayedRedrawRec = NEW[DelayedRedrawRec_[NIL]]; design.delayedRedrawsPriv _ dr; RETURN [dr] }; }; InternalResetDesign: PROC [design: CD.Design] = { dummy: CD.Object _ CDCells.CreateEmptyCell[]; specific: CD.CellSpecific _ NARROW[dummy.specific]; specific.dummyCell _ TRUE; dummy.bbox _ CDBasics.universe; design.cdDirectory1 _ SymTab.Create[]; design.cdDirectory2 _ RefTab.Create[]; design.unDoBuffers _ CD.InitPropRef[]; design^.actual _ LIST[CD.PushRec[ dummyCell: CDInstances.NewInst[ob: dummy], mightReplace: NIL, specific: specific ]]; }; CreateDesign: PUBLIC PROC [technology: CD.Technology] RETURNS [design: CD.Design] = { IF technology=NIL THEN ERROR CD.Error[calling, "NIL technology"]; design _ NEW[CD.DesignRec_[ properties: CD.InitPropRef[], technology: technology, unDoBuffers: CD.InitPropRef[], cdDirectoryPriv2: NEW[LONG POINTER _ NIL] ]]; IF finalizing THEN SafeStorage.EnableFinalization[design]; InternalResetDesign[design]; -- must not cause redraw since event not yet processed [] _ CDEvents.ProcessEvent[createEvent, design]; }; SetMutability: PUBLIC PROC [design: CD.Design, mutability: CD.Mutability _ editable] = { DoIt: ENTRY PROC [] = { ENABLE UNWIND => NULL; IF design.mutability#editable AND design.mutability#findOut THEN RETURN WITH ERROR CD.Error[designMutability]; design.mutability _ mutability; }; IF design=NIL THEN ERROR CD.Error[calling]; IF design.mutability=mutability THEN RETURN; DoIt[]; [] _ CDEvents.ProcessEvent[mutabilityChange, design]; }; ResetDesign: PUBLIC PROC [design: CD.Design] = { InternalResetDesign[design]; [] _ CDEvents.ProcessEvent[resetDesignEvent, design]; design.delayedRedrawsPriv _ NIL; ImmediateRedraw[design]; }; RenameDesign: PUBLIC PROC [design: CD.Design, name: Rope.ROPE] RETURNS [done: BOOL] = { oldName: Rope.ROPE _ design.name; IF Rope.IsEmpty[name] THEN RETURN [FALSE]; done _ ~CDEvents.ProcessEvent[beforeRenameEvent, design, name, TRUE]; IF done THEN { design.name _ name; [] _ CDEvents.ProcessEvent[renameEvent, design, oldName, FALSE]; }; }; RealTopCell: PUBLIC PROC [design: CD.Design] RETURNS [dummyCell: CD.Object] = { FOR l: LIST OF CD.PushRec _ design^.actual, l.rest DO IF l.rest=NIL THEN RETURN [l.first.dummyCell.ob] ENDLOOP }; PushedTopCell: PUBLIC PROC [design: CD.Design] RETURNS [dummyCell: CD.Object] = { RETURN [design^.actual.first.dummyCell.ob]; }; MakeImmutable: PUBLIC PROC [ob: CD.Object] RETURNS [done: BOOL _ TRUE] = { done _ MakeImmutableAndSetNameHints[ob, NIL]; }; MakeImmutableAndSetNameHints: PUBLIC PROC [ob: CD.Object, design: CD.Design] RETURNS [done: BOOL _ TRUE] = { EachChild: CDDirectory.EachObjectProc = { IF ~me.immutable THEN { IF ~MakeImmutableAndSetNameHints[me, design] THEN {done _ FALSE; quit _ TRUE} }; }; IF ~ob.immutable THEN { IF ~ob.class.xDesign THEN [] _ CDDirectory.EnumerateChildObjects[ob, EachChild] ELSE WITH ob.specific SELECT FROM ip: CDImports.ImportSpecific => { bo: CD.Object _ ip.boundOb; IF bo#NIL THEN done _ MakeImmutableAndSetNameHints[bo, ip.boundDesign]; }; ENDCASE => done _ FALSE; IF done THEN { IF design#NIL THEN { name: Rope.ROPE ~ CDDirectory.Name[ob, design]; IF ~Rope.IsEmpty[name] THEN CDProperties.PutObjectProp[ob, $Describe, name]; }; ob.immutable _ TRUE } } }; --xx undelete and friends xxxxxxxxxxxxxxxxxx remSize: CARDINAL = 20; UndeleteBuffer: TYPE = RECORD[ a: ARRAY [0..remSize) OF REF _ ALL[NIL], next: CARDINAL_0 ]; Forgett: PROC [what: REF] = { WITH what SELECT FROM il: CD.InstanceList => FOR l: CD.InstanceList _ il, l.rest WHILE l#NIL DO l.first.properties _ NIL; l.first.ob _ NIL; ENDLOOP; inst: CD.Instance => {inst.properties _ NIL; inst.ob _ NIL}; ENDCASE => NULL; }; GetUndeleteBuffer: PROC [d: CD.Design, create: BOOL_TRUE] RETURNS [buff: REF UndeleteBuffer_NIL] = { WITH CDProperties.GetListProp[d.unDoBuffers^, $delete] SELECT FROM dl: REF UndeleteBuffer => buff _ dl; ENDCASE => IF create THEN { buff _ NEW[UndeleteBuffer]; CDProperties.PutProp[d.unDoBuffers, $delete, buff]; }; }; FlushRemember: PUBLIC PROC [design: CD.Design] = { dl: REF UndeleteBuffer _ GetUndeleteBuffer[design, FALSE]; IF dl#NIL THEN { dl.next _ (dl.next+remSize-1) MOD remSize; DO dl.next _ (dl.next+remSize-1) MOD remSize; IF dl.a[dl.next]=NIL THEN EXIT; Forgett[dl.a[dl.next]]; dl.a[dl.next] _ NIL; ENDLOOP; }; design.unDoBuffers _ CD.InitPropRef[]; }; GetRemembered: PUBLIC PROC [design: CD.Design] RETURNS [CD.InstanceList_NIL] = { GiveRemembered: PROC [d: CD.Design] RETURNS [x: REF] = { dl: REF UndeleteBuffer _ GetUndeleteBuffer[d]; IF dl=NIL THEN RETURN [NIL]; dl.next _ (dl.next+remSize-1) MOD remSize; x _ dl.a[dl.next]; dl.a[dl.next] _ NIL; RETURN [x]; }; WITH GiveRemembered[design] SELECT FROM il: CD.InstanceList => RETURN [il]; inst: CD.Instance => RETURN [LIST[inst]]; ENDCASE => RETURN [NIL]; }; Remember: PUBLIC PROC [design: CD.Design, what: REF] = { dl: REF UndeleteBuffer _ GetUndeleteBuffer[design, TRUE]; Forgett[dl.a[dl.next]]; dl.a[dl.next] _ what; dl.next _ (dl.next+1) MOD remSize; }; --xxxxxxxxxxxxxxxxxxxx RemoveInstance: PUBLIC PROC [design: CD.Design, inst: CD.Instance, draw: BOOL_TRUE] = { il: CD.InstanceList _ CDOps.InstList[design]; IF il#NIL THEN IF il.first=inst THEN CDOps.SetInstList[design, il.rest] ELSE FOR l: CD.InstanceList _ il, l.rest WHILE l.rest#NIL DO IF l.rest.first=inst THEN {l.rest_l.rest.rest; EXIT} ENDLOOP; IF draw THEN Redraw[design, CDInstances.InstRectO[inst]]; }; SelectNewMode: PROC [design: CD.Design] RETURNS [BOOL] = { mode: INT = CDValue.FetchInt[boundTo: design, key: $CDxSelectNewMode, propagation: technology, ifNotFound: 0]; RETURN [mode=1] }; IncludeObject: PUBLIC PROC [design: CD.Design, ob: CD.Object, trans: CD.Transformation] RETURNS [inst: CD.Instance_NIL]= { IF ob=NIL THEN ERROR; inst _ NEW[CD.InstanceRep _ [ob: ob, trans: trans]]; IF SelectNewMode[design] THEN { DeselectAll[design]; inst.selected _ TRUE; }; IncludeInstance[design, inst]; }; FitObjectI: PUBLIC PROC [ob: CD.Object, location: CD.Position _ [0, 0], orientation: CD.Orientation _ CD.Orientation[original]] RETURNS [trans: CD.Transformation] = { trans.orient _ orientation; trans.off _ CDBasics.SubPoints[location, CDBasics.BaseOfRect[CDBasics.MapRect[CD.InterestRect[ob], [[0, 0], orientation]]]]; }; IncludeObjectI: PUBLIC PROC[design: CD.Design, ob: CD.Object, location: CD.Position, orientation: CD.Orientation] RETURNS [CD.Instance]= { RETURN [ IncludeObject[design, ob, FitObjectI[ob, location, orientation]] ]; }; IncludeInstance: PUBLIC PROC [design: CD.Design, inst: CD.Instance, draw: BOOL_TRUE] = { IF inst=NIL THEN ERROR CD.Error[calling, "bad instance"]; IF inst.ob=NIL THEN ERROR CD.Error[calling, "bad object"]; CDOps.SetInstList[design, CONS[inst, CDOps.InstList[design]]]; IF draw THEN Redraw[design, CDInstances.InstRectO[inst], TRUE]; }; IncludeInstanceList: PUBLIC PROC [design: CD.Design, il: CD.InstanceList, draw: BOOL_TRUE] = { FOR list: CD.InstanceList _ il, list.rest WHILE list#NIL DO IncludeInstance[design, list.first, draw]; ENDLOOP; }; ImmediateRedraw: PUBLIC PROC [design: CD.Design, r: CD.Rect_CDOps.all, eraseFirst: BOOL_TRUE] = { CDDrawQueue.InsertDrawCommand[design, CDDrawQueue.Request[IF eraseFirst THEN $redraw ELSE $draw, r]]; }; CheckForShorten: PROC [dl: REF DelayedRedrawRec] = INLINE { IF dl.length>20 THEN { clear: BOOL _ FALSE; r: CD.Rect _ CDBasics.empty; FOR lst: LIST OF DrawDesc _ dl.delayedList, lst.rest WHILE lst#NIL DO clear _ clear OR lst.first.clear; r _ CDBasics.Surround[r, lst.first.area] ENDLOOP; dl.delayedList _ LIST[DrawDesc[area: r, clear: clear]]; dl.length _ 1 }; }; Redraw: PUBLIC ENTRY PROC [design: CD.Design, r: CD.Rect, eraseFirst: BOOL_TRUE] = { ENABLE UNWIND => NULL; IF design#NIL THEN { dl: REF DelayedRedrawRec = GetDelayedRedrawRef[design]; IF dl.delayedList=NIL THEN { dl.delayedList _ LIST[DrawDesc[area: r, clear: eraseFirst]]; dl.length _ 1 } ELSE { list: LIST OF DrawDesc _ dl.delayedList; DO IF CDBasics.Intersect[list.first.area, r] THEN { IF CDBasics.Inside[r, list.first.area] THEN { list.first.clear _ list.first.clear OR eraseFirst; RETURN } ELSE IF CDBasics.Inside[list.first.area, r] THEN { remember: LIST OF DrawDesc _ list; eraseFirst _ list.first.clear OR eraseFirst; list.first.area _ r; WHILE list.rest#NIL DO IF CDBasics.Inside[list.rest.first.area, r] THEN { eraseFirst _ list.rest.first.clear OR eraseFirst; list.rest _ list.rest.rest; --does not change list -> keeps assertion3 dl.length _ dl.length-1; } ELSE list _ list.rest --since list.rest#NIL -> keeps assertion3 ENDLOOP; remember.first.clear _ eraseFirst; RETURN } }; IF list.rest#NIL THEN list_list.rest ELSE { list.rest _ LIST[DrawDesc[area: r, clear: eraseFirst]]; dl.length _ dl.length+1; CheckForShorten[dl]; RETURN } ENDLOOP; } --of dl.delayedList#NIL } --of design#NIL }; DoTheDelayedRedraws: PUBLIC ENTRY PROC [design: CD.Design] = { ENABLE UNWIND => NULL; sq: REF DelayedRedrawRec; sq _ GetDelayedRedrawRef[design]; UNTIL sq.delayedList=NIL DO CDDrawQueue.InsertDrawCommand[design, CDDrawQueue.Request[(IF sq.delayedList.first.clear THEN $redraw ELSE $draw), sq.delayedList.first.area]]; sq.delayedList _ sq.delayedList.rest ENDLOOP; sq.length _ 0; }; RedrawInstance: PUBLIC PROC [design: CD.Design, inst: CD.Instance_NIL, erase: BOOL_TRUE] = { IF inst#NIL THEN Redraw[design, CDInstances.InstRectO[inst], erase] ELSE Redraw[design, CDBasics.universe, erase] }; DrawDesign: PUBLIC PROC[design: CD.Design, pr: CD.DrawRef] = { IF pr.selections THEN FOR il: CD.InstanceList _ CDOps.InstList[design], il.rest WHILE il#NIL DO IF il.first.selected AND CDBasicsInline.IntersectRI[pr.interestClip, il.first] THEN { IF pr.stopFlag^ THEN RETURN; pr.drawChildSel[pr, il.first.ob, il.first.trans]; }; ENDLOOP; FOR il: CD.InstanceList _ CDOps.InstList[design], il.rest WHILE il#NIL DO IF CDBasicsInline.IntersectRI[pr.interestClip, il.first] THEN { IF pr.stopFlag^ THEN RETURN; pr.drawChild[pr, il.first.ob, il.first.trans, il.first.properties]; } ENDLOOP; IF pr.environment THEN FOR w: LIST OF CD.PushRec _ design^.actual.rest, w.rest WHILE w#NIL DO IF pr.stopFlag^ THEN RETURN; pr.drawChild[pr, w.first.dummyCell.ob, [[0, 0], original]]; ENDLOOP; }; QuickDrawDesign: PUBLIC PROC [design: CD.Design, pr: CD.DrawRef] = { QuickDrawPushedCell: PROC [cp: CD.CellSpecific, pr: CD.DrawRef] = INLINE { IF pr.borders AND cp.drawBorder THEN pr.drawOutLine[pr, cp.ir, CD.outlineLayer]; FOR w: CD.InstanceList _ cp.contents, w.rest WHILE w#NIL DO IF CDBasicsInline.IntersectRI[pr.interestClip, w.first] THEN { IF pr.stopFlag^ THEN EXIT; w.first.ob.class.quickDrawMe[pr, w.first.ob, w.first.trans, w.first.properties]; } ENDLOOP; }; pr.setGround[pr: pr, pushedOut: FALSE]; FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF w.first.selected AND CDBasicsInline.IntersectRI[pr.interestClip, w.first] THEN { IF pr.stopFlag^ THEN RETURN; w.first.ob.class.quickDrawMe[pr, w.first.ob, w.first.trans, w.first.properties]; IF pr.selections THEN w.first.ob.class.showMeSelected[pr, w.first.ob, w.first.trans, w.first.properties]; }; ENDLOOP; FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF ~w.first.selected AND CDBasicsInline.IntersectRI[pr.interestClip, w.first] THEN { IF pr.stopFlag^ THEN RETURN; w.first.ob.class.quickDrawMe[pr, w.first.ob, w.first.trans, w.first.properties]; }; ENDLOOP; IF design^.actual.rest#NIL THEN { pr.drawOutLine[pr, design^.actual.first.specific.ir, CD.outlineLayer]; IF pr.environment THEN { pr.setGround[pr: pr, pushedOut: TRUE]; FOR w: LIST OF CD.PushRec _ design^.actual.rest, w.rest WHILE w#NIL DO IF pr.stopFlag^ THEN RETURN; QuickDrawPushedCell[w.first.specific, pr]; ENDLOOP; }; }; }; SelectedInstance: PUBLIC PROC [design: CD.Design] RETURNS [first: CD.Instance_NIL, multiple: BOOL_FALSE] = { FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF w.first.selected THEN IF first=NIL THEN first_w.first ELSE {multiple_TRUE; RETURN} ENDLOOP; }; TheInstance: PUBLIC PROC [design: CD.Design, text: Rope.ROPE_NIL] RETURNS [inst: CD.Instance_NIL] = { multiple: BOOL; IF text#NIL THEN TerminalIO.PutRope[text]; [inst, multiple] _ SelectedInstance[design]; IF multiple THEN {TerminalIO.PutRope[" multiple selection; failed\n"]; RETURN [NIL]}; IF inst=NIL THEN {TerminalIO.PutRope[" no selection; failed\n"]; RETURN [NIL]}; IF inst.ob=NIL THEN {inst_NIL; TerminalIO.PutRope[" bad object; failed\n"]}; }; LayerRope: PUBLIC PROC [layer: CD.Layer] RETURNS [Rope.ROPE] = { uniqueKey: ATOM = CD.LayerKey[layer]; IF uniqueKey=NIL THEN RETURN ["bad layer"]; RETURN [Atom.GetPName[uniqueKey]] }; InstRope: PUBLIC PROC [inst: CD.Instance, design: CD.Design, verbosity: INT_0] RETURNS [r: Rope.ROPE] = { IF inst=NIL THEN r _ "nil instance" ELSE r _ CD.Describe[inst.ob, inst.properties, design, verbosity]; }; ToRope: PUBLIC PROC [x: REF, whenFailed: REF_NIL] RETURNS [rope: Rope.ROPE_NIL] = { WITH x SELECT FROM r: Rope.ROPE => rope _ r; rt: REF TEXT => rope _ Rope.FromRefText[rt]; ri: REF INT => rope _ Convert.RopeFromInt[ri^]; a: ATOM => rope _ Atom.GetPName[a]; l: CDPrivate.LayerRef => rope _ CDOps.LayerRope[l.number]; ob: CD.Object => rope _ CD.Describe[ob]; inst: CD.Instance => rope _ CD.Describe[inst.ob, inst.properties]; d: CD.Design => rope _ d.name; t: CD.Technology => rope _ t.name; rc: REF LONG CARDINAL => rope _ Convert.RopeFromCard[rc^]; ri: REF INTEGER => rope _ Convert.RopeFromInt[ri^]; ri: REF NAT => rope _ Convert.RopeFromInt[ri^]; rc: REF CARDINAL => rope _ Convert.RopeFromCard[rc^]; ENDCASE => SELECT whenFailed FROM NIL => rope _ NIL; $Interactive => { RopeNeeded: SIGNAL [ ref: REF REF ] = CODE; refRef: REF REF = NEW[REF _ x]; TerminalIO.PutRope["please enter a ROPE using the debugger"]; SIGNAL RopeNeeded[refRef]; rope _ ToRope[refRef^ ! RopeNeeded => ERROR]; }; ENDCASE => rope _ ToRope[whenFailed]; }; LambdaRope: PUBLIC PROC [n: CD.Number, lambda: CD.Number_1] RETURNS [Rope.ROPE] = { IF n MOD lambda = 0 THEN RETURN IO.PutFR1[" %g", IO.int[n/lambda]] ELSE { r: Rope.ROPE _ " ("; IF n<0 THEN {n _ ABS[n]; r _ " -("}; IF n/lambda>0 THEN r _ IO.PutFR["%0g%0g+", IO.rope[r], IO.int[n/lambda]]; RETURN [IO.PutFR["%0g%0g/%0g)", IO.rope[r], IO.int[n MOD lambda], IO.int[lambda]]]; } }; ReOrderInstance: PUBLIC PROC [design: CD.Design, inst: CD.Instance] = { il: CD.InstanceList _ CDOps.InstList[design]; found: BOOL _ FALSE; IF inst=NIL THEN ERROR CD.Error[calling, "Reorder of NIL application"]; WHILE il#NIL AND il.first=inst DO {found_TRUE; il _ il.rest} ENDLOOP; IF il=NIL THEN { IF found THEN il_LIST[inst] ELSE ERROR CD.Error[calling, "Reorder of application not in design"]; } ELSE FOR l: CD.InstanceList _ il, l.rest DO WHILE l.rest#NIL AND l.rest.first=inst DO {found_TRUE; l.rest _ l.rest.rest} ENDLOOP; IF l.rest=NIL THEN { IF found THEN l.rest _ LIST[inst] ELSE ERROR CD.Error[calling, "reorder finds bad instance"]; EXIT } ENDLOOP; CDOps.SetInstList[design, il]; }; GetGrid: PUBLIC PROC [design: CD.Design, hint: REF_NIL] RETURNS [CD.Number] = { RETURN [CDPrivate.GetGrid[design, hint]] }; PlaceInst: PUBLIC PROC [design: CD.Design, ob: CD.Object, hint: REF_NIL] RETURNS [inst: CD.Instance] = { lambda: CD.Number _ design.technology.lambda; space, w1, w2: CD.Number; grid: CD.Number _ MAX[1, GetGrid[design, hint]]; bb: CD.Rect _ CDOps.BoundingBox[design]; IF ~CDBasics.NonEmpty[bb] THEN bb _ [0, 0, 0, 0]; w1 _ MAX[lambda*5, bb.x2-bb.x1]; w2 _ MAX[lambda*5, CD.InterestSize[ob].x]; space _ MIN[w1, w2]/8+MAX[w1, w2]/80+lambda*4; inst _ CDInstances.NewInst[ob: ob, trans: [[(bb.x2+space+grid-1)/grid*grid, (bb.y1+grid-1)/grid*grid]] ]; CDOps.IncludeInstance[design, inst]; }; BoundingBox: PUBLIC PROC [design: CD.Design, onlySelected: BOOL] RETURNS [r: CD.Rect _ CDBasics.empty] = { IF onlySelected THEN r _ CDInstances.BoundingRectO[CDOps.InstList[design], TRUE] ELSE FOR l: LIST OF CD.PushRec _ design.actual, l.rest WHILE l#NIL DO r _ CDBasics.Surround[r, CDInstances.BoundingRectO[ NARROW[l.first.dummyCell.ob.specific, CD.CellSpecific].contents ]] ENDLOOP; }; DeselectAll: PUBLIC PROC [design: CD.Design, setSelection: BOOL_FALSE] = { bb: CD.Rect _ CDBasics.empty; cnt: INT _ 0; FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF w.first.selected#setSelection THEN { cnt_cnt+1; bb _ CDBasics.Surround[bb, CDInstances.InstRectO[w.first]]; } ENDLOOP; FOR w: CD.InstanceList _ CDOps.InstList[design], w.rest WHILE w#NIL DO IF w.first.selected#setSelection THEN { w.first.selected _ setSelection; IF cnt>10 THEN RedrawInstance[design, w.first, ~setSelection] }; ENDLOOP; IF cnt<=10 THEN Redraw[design, bb, ~setSelection] }; DrawCollected: CD.DrawProc = { pr.drawRect[pr, CDBasics.MapRect[ob.bbox, trans], CD.errorLayer] }; ReadCollected: CD.InternalReadProc = { r: Rope.ROPE = "*design of this object has been destroyed; bug in creator program\n"; ob: CD.Object _ NEW[CD.ObjectRep_[class: gCollectedClass, layer: CD.errorLayer]]; IF CDIO.VersionKey[h]<=16 THEN ob.bbox _ CDBasics.RectAt[[0, 0], CDIO.ReadPos[h]] ELSE ob.bbox _ CDIO.ReadRect[h]; CDProperties.PutObjectProp[ob, $SignalName, r]; ob.immutable _ TRUE; TerminalIO.PutRope[r]; RETURN [ob] }; WriteCollected: CD.InternalWriteProc = { CDIO.WriteRect[h, ob.bbox]; TerminalIO.PutRope["*write object which has been destroyed\n"]; }; gCollectedClass: CD.ObjectClass = CD.RegisterObjectClass[$GCollected, [ drawMe: DrawCollected, quickDrawMe: DrawCollected, internalRead: ReadCollected, internalWrite: WriteCollected, description: "garbage object; design has been destroyed" ]]; DestroyEachObject: CDDirectory.EachObjectProc = { IF ~me.immutable AND (me.class=NIL OR me.class.composed) THEN { me.class _ gCollectedClass; me.layer _ CD.errorLayer; me.properties _ NIL; }; }; FinalizeDesign: PROC [d: CD.Design] = { IF d.mutability=findOut THEN TRUSTED { Process.Detach[FORK TerminalIO.PutF["%l**design %g garbage collected before mutability was set%l\n", IO.rope["ib"], IO.rope[CD.DesignName[d]], IO.rope[" "] ] ]; }; IF d.mutability=editable OR d.mutability=readonly THEN { IF d.cdDirectory1#NIL AND d.cdDirectory2#NIL AND CDValue.Fetch[d, $DontGC]=NIL THEN [] _ CDDirectory.EnumerateDesign[design: d, proc: DestroyEachObject, dir: TRUE, top: TRUE, recurse: TRUE, dummy: TRUE]; WHILE d.actual#NIL DO d.actual.first.dummyCell.properties _ NIL; IF d.actual.first.mightReplace#NIL THEN d.actual.first.mightReplace.properties _ NIL; d.actual _ d.actual.rest; ENDLOOP; }; }; FinalizerProcess: PROC[fooFQ: SafeStorage.FinalizationQueue] = { DO d: CD.Design = NARROW[SafeStorage.FQNext[fooFQ]]; FinalizeDesign[d ! RuntimeError.UNCAUGHT => CONTINUE]; ENDLOOP }; mutabilityChange: CDEvents.EventRegistration = CDEvents.RegisterEventType[$MutabilityChange]; finalizing: BOOL = UserProfile.Boolean["ChipNDale.DoFinalization", TRUE]; IF finalizing THEN { fooFQ: SafeStorage.FinalizationQueue = SafeStorage.NewFQ[]; IF Atom.GetProp[$ChipNDalePrivate, $FinalizationEnabled]=$TRUE THEN SafeStorage.ReEstablishFinalization[CODE[CD.DesignRec], 0, fooFQ] ELSE { SafeStorage.EstablishFinalization[CODE[CD.DesignRec], 0, fooFQ]; Atom.PutProp[$ChipNDalePrivate, $FinalizationEnabled, $TRUE]; }; TRUSTED {Process.Detach[FORK FinalizerProcess[fooFQ]]}; }; CDValue.RegisterKey[$DontGC]; END. ϊCDOpsImpl.mesa (part of ChipNDale) Copyright c 1983, 1987 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, July 12, 1983 10:56 am Last edited by: Christian Jacobi, August 20, 1987 2:03:20 pm PDT --is local since it does not cause a redraw --helps the garbage collector and may prevent circularities through properties --ASSERTION1: {list#NIL} --ASSERTION2: {no list rectangle is completely covered by an other one} --r is contained somewhere; we dont include it --it is unlikely that a small area is cleared and a big one not --assertion2 => no other elements could be removed --r contains an element; we remove this element and all others -- which are contained in r --it is unlikely that a small area is cleared and a big one not --remove all other element contained in r; to maintain assertion2 assert3: list#NIL --selections of the top level cell --the top level cell --the pushed in cells --top level selections --top level non selections --the pushed in cells --first: returns ref to any selected application if there is one or more, otherwise nil. --multiple: more than one application is selected --on return: design has exactly one occurrence of inst, and it is at the end. --(includes inst if necessary and removes double occurences) -- l#NIL AND l.first#inst holds at this point -- xxxxxxxxxxxxxxxx -- Finalization -- -- designs are finalized to break circularities involving objects or instances --don't access specific; in error case, some procedure might be on its way Κš˜codešœ(™(Kšœ Οmœ7™BKšœ4™4K™@—K˜šΟk ˜ Kšœ˜Kšžœ˜Kšœ ˜ Kšœ˜K˜Kšœ ˜ Kšœ ˜ K˜ K˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœž˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ žœžœ˜Kšœ ˜ Kšœ ˜ —K˜šΟn œžœžœ˜KšžœžœVžœ‰˜σKšžœ˜Kšžœžœ˜ —Kšž˜K˜UK˜VK˜TK˜`K˜Kš œ žœžœžœžœ˜5šœžœžœ˜!Kšœ žœžœ žœ˜"Kšœžœ˜K˜—K˜š Ÿœžœ žœ žœžœ˜Pšžœžœž˜*Kšœžœžœ˜(šžœ˜ Kšœžœžœžœ˜7Kšœ˜Kšžœ˜ K˜——Kšœ˜K˜—K˜šŸœžœ žœ ˜1KšΟc+™+Kšœžœ$˜-Kšœ žœžœ˜4Kšœžœ˜Kšœ˜Kšœ&˜&Kšœ&˜&Kšœžœ˜&šœžœžœ ˜!Kšœ*˜*Kšœžœ˜Kšœ˜Kšœ˜—Kšœ˜—K˜š Ÿ œžœžœžœ žœ žœ ˜UKš žœ žœžœžœžœ"˜Ašœ žœžœ ˜Kšœ žœ˜Kšœ˜Kšœ žœ˜Kš œžœžœžœžœ˜*Kšœ˜—Kšžœ žœ(˜:Kšœ 6˜SK˜1Kšœ˜—K˜š Ÿ œžœžœ žœžœ˜XšŸœžœžœ˜Kšžœžœžœ˜šžœžœžœ˜AKšžœžœžœžœ˜-—Kšœ˜Kšœ˜—Kš žœžœžœžœžœ˜+Kšžœžœžœ˜,Kšœ˜Kšœ5˜5Kšœ˜—K˜šŸ œžœžœ žœ ˜0Kšœ˜K˜6Kšœžœ˜ Kšœ˜Kšœ˜K˜—šŸ œžœžœ žœžœžœžœ˜WKšœžœ˜!Kšžœžœžœžœ˜*Kšœ?žœ˜Ešžœžœ˜Kšœ˜Kšœ9žœ˜@K˜—Kšœ˜—K˜š Ÿ œž œ žœ žœ žœ ˜Oš žœžœžœžœ"ž˜5Kšžœžœžœžœ˜0Kšž˜—K˜—K˜š Ÿ œž œ žœ žœ žœ ˜QKšžœ%˜+K˜—K˜šŸ œžœžœžœ žœžœžœ˜JJšœ(žœ˜-J˜—K˜šŸœžœžœžœžœ žœžœžœ˜lšŸ œ ˜)šžœžœ˜Jšžœ+žœ žœ žœ˜MJšœ˜—J˜—šžœžœ˜šžœ˜Jšžœ7˜;šžœžœ žœž˜!šœ!˜!Jšœžœ˜šžœžœžœ˜Jšœ8˜8—Jšœ˜—Jšžœ žœ˜——šžœžœ˜šžœžœžœ˜Jšœ žœ ˜/Jšžœžœ1˜LJ˜—Jšœž˜J˜—J˜—J˜—K˜Kšœ,˜,K˜Kšœ žœ˜šœžœžœ˜Kš œžœžœžœžœžœ˜(Kšœžœ˜Kšœ˜—K˜šŸœžœžœ˜Kš N™Nšžœžœž˜šœžœ˜š žœžœžœžœž˜2Kšœžœžœ˜+Kšžœ˜——Kšœžœ žœ žœ˜Kšžœžœ-žœ˜?Kšœ˜—K˜šŸœžœžœ žœ žœžœžœ˜^š žœžœžœžœž˜;Kšœ*˜*Kšž˜—Kšœ˜—K˜šŸœžœžœ žœ žœžœžœ˜aKšœ:žœ žœ žœ ˜eKšœ˜K˜—K˜šŸœžœžœžœ˜;šžœžœ˜Kšœžœžœ˜Kšœžœ˜š žœžœžœ%žœžœž˜EKšœžœ˜!Kšœ(˜(Kšžœ˜—Kšœžœ"˜7Kšœ ˜ K˜—K˜—K˜šŸœžœžœžœ žœ žœžœžœ˜TKšžœžœžœ˜šžœžœžœ˜Kšœžœ0˜7šžœžœžœ˜Kšœžœ'˜=Kšœ ˜ Kšœ˜—šžœ˜Kšœžœžœ˜(šž˜Kšœ™KšœG™Gšžœ(žœ˜0šžœ%žœ˜.K™.Kšœ?™?Kšœ$žœ ˜2Kšœ2™2Kšž˜K˜—šžœžœ%žœ˜2K™>K™Kšœ?™?Kšœ žœžœ˜"Kšœžœ ˜,Kšœ˜KšœA™Ašžœ žœž˜Kšœ™šžœ*žœ˜2Kšœ#žœ ˜1Kšœ *˜FKšœ˜K˜—Kšžœ )˜?Kšžœ˜—Kšœ"˜"Kšž˜K˜—K˜—Kšžœ žœžœ˜$šžœ˜Kšœ žœ'˜7Kšœ˜Kšœ˜Kšž˜K˜—Kšžœ˜—Kšœ ˜—Kšœ ˜—Kšœ˜—K˜š Ÿœžœžœžœ žœ ˜>Kšžœžœžœ˜Kšœžœ˜Kšœ!˜!šžœžœž˜Kšœ:žœžœ žœ%˜Kšœ$˜$Kšžœ˜—Kšœ˜Kšœ˜—K˜šŸœžœžœ žœžœ žœ žœžœ˜\Kšžœžœžœ3˜CKšžœ)˜-Kšœ˜—K˜š Ÿ œžœžœ žœ žœ ˜>Kš "™"šžœž˜š žœžœ0žœžœž˜Išžœžœ7žœ˜UKšžœžœžœ˜Kšœ1˜1K˜—Kšžœ˜——Kš ™š žœžœ0žœžœž˜Išžœ7žœ˜?Kšžœžœžœ˜KšœC˜CK˜—Kšžœ˜—Kš ™šžœž˜š žœžœžœžœ'žœžœž˜FKšžœžœžœ˜Kšœ;˜;Kšžœ˜——Kšœ˜K˜—š Ÿœžœžœ žœ žœ ˜DK˜š Ÿœžœžœžœ žœ˜JKšžœ žœžœžœ˜Pš žœžœ$žœžœž˜;šžœ6žœ˜>Kšžœžœžœ˜KšœP˜PK˜—Kšžœ˜—Kšœ˜—K™Kšœ žœ˜'Kšœ™š žœžœ/žœžœž˜Fšžœžœ6žœ˜SKšžœžœžœ˜K˜Pšžœž˜K˜S—Kšœ˜—Kšžœ˜—Kšœ™š žœžœ/žœžœž˜Fšžœžœ6žœ˜TKšžœžœžœ˜K˜PKšœ˜—Kšžœ˜—Kšœ™šžœžœžœ˜!Kšœ5žœ˜Fšžœžœ˜Kšœ žœ˜&š žœžœžœžœ'žœžœž˜FKšžœžœžœ˜Kšœ*˜*Kšžœ˜—K˜—K˜—Kšœ˜—K˜š Ÿœž œ žœ žœ žœž œ˜lšœX™XKšœ1™1—š žœžœ/žœžœž˜Fšžœž˜Kšžœžœžœ˜Kšžœ žœžœ˜—Kšžœ˜—Kšœ˜K˜—šŸ œžœžœ žœžœžœžœžœ žœ˜eKšœ žœ˜Kšžœžœžœ˜*Kšœ,˜,Kšžœ žœ9žœžœ˜WKš žœžœžœ3žœžœ˜QKšžœ žœžœžœ1˜NKšœ˜K˜—š Ÿ œžœžœžœžœžœ˜@Kšœ žœžœ˜%Kšžœ žœžœžœ˜,Kšžœ˜!Kšœ˜—K˜šŸœžœžœžœ)žœžœ žœ˜iKšžœžœžœ˜#Kšžœžœ7˜BKšœ˜—K˜šŸœžœžœžœžœžœžœ žœžœ˜Sšžœžœž˜Kšœžœ ˜Kšœžœžœ ˜,Kšœžœžœ$˜/Kšœžœ˜#Kšœ;˜;Kšœžœžœ˜(Kšœžœžœ$˜BKšœžœ˜Kšœžœ˜#Kšœžœžœžœ%˜:Kšœžœžœ$˜3Kšœžœžœ$˜/Kšœžœžœ%˜5šžœ˜ šžœ ž˜Kšžœ žœ˜˜Kš Ÿ œžœžœžœžœ˜+Kš œžœžœžœžœ˜Kšœ=˜=Kšžœ˜Kšœ&žœ˜-K˜—Kšžœ˜%———Kšœ˜—K˜šŸ œžœžœžœžœ žœžœ˜SKš žœžœ žœžœžœžœ˜Bšžœ˜Kšœžœ˜Kšžœžœžœ˜$Kš žœ žœžœžœ žœ˜JKš žœžœžœ žœžœ žœ˜SK˜—Kšœ˜—K˜š Ÿœžœžœ žœžœ˜GKšœN™NK™