File: BluejayToolImpl.mesa
This file contains routines to initialize the Bluejay window and
top-level command processing routines.
Last edited by:
John Ousterhout  July 28, 1982 5:09 pm
Last Edited by: Stewart, December 30, 1983 11:17 am
DIRECTORY
BluejayTool,
ChoiceButtons USING [BuildEnumTypeSelection, BuildTextPrompt, EnumTypeRef, PromptDataRef, SelectionNotifierProc],
Containers USING [ChildXBound, ChildYBound, Container, Create],
Convert USING [IntFromRope],
IO,
Jukebox,
Labels USING [Create],
Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc],
Rope USING [Cat, Equal, ROPE, Size],
TypeScript USING [Create],
VFonts USING [FontHeight],
ViewerClasses USING [Viewer],
ViewerEvents USING [EventProc, RegisterEventProc],
ViewerOps USING [OpenIcon, PaintViewer],
ViewerIO USING [CreateViewerStreams],
ViewerTools USING [GetContents, SetContents],
VoiceStream USING [StartMonitor, StartServer];
BluejayToolImpl: CEDAR PROGRAM
IMPORTS ChoiceButtons, Containers, Convert, IO, Jukebox, Labels, Menus, Rope, TypeScript, VFonts, ViewerEvents, ViewerOps, ViewerIO, ViewerTools, VoiceStream
EXPORTS BluejayTool
SHARES BluejayTool =
BEGIN
Viewers for outer container and parameters:
container: Containers.Container ← NIL;
jukeboxNameViewer: ChoiceButtons.PromptDataRef;
jukeboxSizeViewer: ChoiceButtons.PromptDataRef;
nTunesViewer: ChoiceButtons.PromptDataRef;
tunesInUse: ViewerClasses.Viewer ← NIL;
chirpsInUse: ViewerClasses.Viewer ← NIL;
chirpViewer: ViewerClasses.Viewer ← NIL;
jukebox: Jukebox.Handle ← NIL;
TrueFalseRecord: TYPE = RECORD [
value: BOOL,
trueRope: Rope.ROPE,
falseRope: Rope.ROPE,
button: ChoiceButtons.EnumTypeRef
];
TrueFalse: TYPE = REF TrueFalseRecord;
gcFixup: TrueFalse ← NEW[TrueFalseRecord ← [FALSE, "Correct inconsistencies during garbage collection", "Don't correct inconsistencies during garbage collection", NIL]];
btDebug: TrueFalse ← NEW[TrueFalseRecord ← [FALSE, "Enter Bugbane on uncaught signals", "Unwind after uncaught signals", NIL]];
Variables for parameters:
jukeboxSize: LONG INTEGER;
nTunes: LONG INTEGER;
Typescript handle:
stream: IO.STREAMNIL;
Enumerated type for different commands (so we can have one central command
processing routine and thereby only have to declare signal handlers once).
Command: TYPE = {create, open, close, scavenge, delete};
SetTrueFalse: ChoiceButtons.SelectionNotifierProc = {
tf: TrueFalse ← NARROW[clientdata];
tf.value ← Rope.Equal[name, tf.trueRope];
};
Init: PROC = {
streamViewer: ViewerClasses.Viewer ← NIL;
lineHeight: INT ← VFonts.FontHeight[] + 3;
data: Rope.ROPENIL;
myMenu: Menus.Menu ← Menus.CreateMenu[];
Create menu entries.
x: INTEGER ← 1;
y: INTEGER ← 0;
newline: BOOLFALSE;
child: ViewerClasses.Viewer;
LabelText: PROC[name, data: Rope.ROPE]
RETURNS [p: ChoiceButtons.PromptDataRef] =
{
child: ViewerClasses.Viewer;
p ← ChoiceButtons.BuildTextPrompt[viewer: container, x: x+1, y: y, title: name, default: data];
child ← p.promptButton;
x ← 1;
y ← child.wy + child.wh + 1;
RETURN[p]
};
Label: PROC[name: Rope.ROPE, newline: BOOL] RETURNS [ViewerClasses.Viewer] =
{
child ← Labels.Create[
info: [name: name, parent: container, border: FALSE,
wy: y, wx: x+1],
paint: TRUE ];
x ← IF newline THEN 1 ELSE child.wx + child.ww - 1;
y ← IF newline THEN child.wy + child.wh - 1 ELSE child.wy;
RETURN[child];
};
Menus.AppendMenuEntry[menu: myMenu,
entry: Menus.CreateEntry[name: "Create",
proc: command,
clientData: NEW[Command ← create]]];
Menus.AppendMenuEntry[menu: myMenu,
entry: Menus.CreateEntry[name: "Open",
proc: command,
clientData: NEW[Command ← open]]];
Menus.AppendMenuEntry[menu: myMenu,
entry: Menus.CreateEntry[name: "Close",
proc: command,
clientData: NEW[Command ← close]]];
Menus.AppendMenuEntry[menu: myMenu,
entry: Menus.CreateEntry[name: "Scavenge",
proc: command,
clientData: NEW[Command ← scavenge]]];
Menus.AppendMenuEntry[menu: myMenu,
entry: Menus.CreateEntry[name: "Delete",
proc: command,
clientData: NEW[Command ← delete]]];
Create the container that will hold all this stuff.
container ← Containers.Create[[name: "Bluejay", iconic: TRUE,
openHeight: 300, menu: myMenu, scrollable: FALSE]];
Add parameter labels and buttons.
jukeboxNameViewer ← LabelText[name: "Jukebox name:", data: "test"];
jukeboxSizeViewer ← LabelText[name: "Size:", data: "5000"];
nTunesViewer ← LabelText[name: "# Tunes:", data: "20"];
tunesInUse ← Label[name: "Tunes In Use: unknown ", newline: FALSE];
chirpsInUse ← Label[name: "Chirps In Use: unknown ", newline: TRUE];
gcFixup.button ← ChoiceButtons.BuildEnumTypeSelection[viewer: container, x: 0, y: y, buttonNames: LIST[gcFixup.trueRope, gcFixup.falseRope], default: gcFixup.falseRope, notifyClientProc: SetTrueFalse, clientdata: gcFixup, style: flipThru];
y ← y+lineHeight+3;
btDebug.button ← ChoiceButtons.BuildEnumTypeSelection[viewer: container, x: 0, y: y, buttonNames: LIST[btDebug.trueRope, btDebug.falseRope], default: btDebug.falseRope, notifyClientProc: SetTrueFalse, clientdata: btDebug, style: flipThru];
y ← y+lineHeight+3;
Create information area for voice streams.
TRUSTED { y ← VoiceStream.StartMonitor[container: container, y: y]; };
Create a stream for the log.
streamViewer ← TypeScript.Create[info: [parent: container,
wx: 0, wy: y, ww: 500, wh: 800, border: FALSE]];
Containers.ChildXBound[container, streamViewer];
Containers.ChildYBound[container, streamViewer];
[out: stream] ← ViewerIO.CreateViewerStreams[viewer: streamViewer,
name: "Bluejay output"];
ViewerOps.OpenIcon[container];
Make sure we get notified if the viewer is destroyed.
[] ← ViewerEvents.RegisterEventProc[proc: destroyProc, event: destroy];
};
checkParms: PROC = {
This procedure reads in the strings from parameter viewers and updates
the integers that they correspond to.
r: Rope.ROPE;
r ← ViewerTools.GetContents[jukeboxSizeViewer.textViewer];
IF Rope.Size[r] = 0 THEN jukeboxSize ← 0
ELSE jukeboxSize ← Convert.IntFromRope[r];
r ← ViewerTools.GetContents[nTunesViewer.textViewer];
IF Rope.Size[r] = 0 THEN nTunes ← 0
ELSE nTunes ← Convert.IntFromRope[r];
};
GetBluejayLogStream: PUBLIC PROC RETURNS [IO.STREAM] = { RETURN[stream]; };
UpdateViewer: PUBLIC PROC = {
name: Rope.ROPE ← NIL;
nPages, nTunes: INT ← 0;
TRUSTED {
IF jukebox # NIL THEN [name: name, nPages: nPages, nTunes: nTunes] ← Jukebox.Info[jukebox];
};
IF name = NIL THEN {
container.name ← "Bluejay (no jukebox open)";
}
ELSE {
container.name ← Rope.Cat["Bluejay: jukebox is ", name];
ViewerTools.SetContents[viewer: nTunesViewer.textViewer,
contents: IO.PutFR["%d", IO.int[nTunes]],
paint: TRUE];
ViewerTools.SetContents[viewer: jukeboxSizeViewer.textViewer,
contents: IO.PutFR["%d", IO.int[nPages]],
paint: TRUE];
ViewerTools.SetContents[viewer: tunesInUse,
contents: IO.PutFR["Tunes In Use: %d", IO.int[0]],
paint: TRUE];
ViewerTools.SetContents[viewer: chirpsInUse,
contents: IO.PutFR["Chirps In Use: %d", IO.int[0]],
paint: TRUE];
};
ViewerOps.PaintViewer[container, caption];
};
command: Menus.MenuProc = TRUSTED {
ENABLE {
VoiceStream.Error => {
MessageWindow.Append[rope, TRUE];
MessageWindow.Blink[];
IF btDebug.value THEN REJECT;
CONTINUE;
};
Jukebox.Error => {
MessageWindow.Append[rope, TRUE];
MessageWindow.Blink[];
IF btDebug.value THEN REJECT;
CONTINUE;
};
Jukebox.MissingChirp => {
MessageWindow.Append["Missing chirp.", TRUE];
MessageWindow.Blink[];
IF btDebug.value THEN REJECT;
CONTINUE;
};
Jukebox.EOF => {
MessageWindow.Append["End of jukebox file.", TRUE];
MessageWindow.Blink[];
IF btDebug.value THEN REJECT;
CONTINUE;
};
AMEvents.Debugging, AMEvents.Debugged => REJECT;
ABORTED => CONTINUE;
ANY => {
MessageWindow.Append["Unknown error signal.", TRUE];
MessageWindow.Blink[];
IF btDebug.value THEN REJECT;
CONTINUE;
};
};
command: REF Command ← NARROW[clientData];
checkParms[];
SELECT command^ FROM
Create jukebox.
create => {
name: Rope.ROPE ← ViewerTools.GetContents[jukeboxNameViewer.textViewer];
Jukebox.CreateJukebox[nPages: jukeboxSize, nTunes: nTunes, name: name];
UpdateViewer[];
};
Open jukebox.
open => {
name: Rope.ROPE ← ViewerTools.GetContents[jukeboxNameViewer.textViewer];
jukebox ← Jukebox.OpenJukebox[name: name];
UpdateViewer[];
};
Close jukebox.
close => {
jukebox ← Jukebox.CloseJukebox[jukebox];
UpdateViewer[];
};
Scavenge.
scavenge => {
i, j: LONG INTEGER;
[nFree: i, recovered: j] ← Jukebox.Scavenge[jukebox, stream, gcFixup.value];
IO.PutF[stream, "Recovered %d chirps, free list size now %d.\n",
IO.int[j], IO.int[i]];
};
delete => {
name: Rope.ROPE ← ViewerTools.GetContents[jukeboxNameViewer.textViewer];
Jukebox.DeleteJukebox[name: name];
};
ENDCASE;
};
The following procedure is called when the viewer is destroyed.
It cleans up the jukebox.
destroyProc: ViewerEvents.EventProc = TRUSTED {
IF viewer # container OR event # destroy THEN RETURN;
IF jukebox # NIL THEN jukebox ← Jukebox.CloseJukebox[jukebox ! ANY => CONTINUE];
};
Init[];
TRUSTED { VoiceStream.StartServer[stream]; };
END.
Last Edited by: Swinehart, March 1, 1983 3:11 pm
Last Edited by: Stewart, May 22, 1983 6:37 pm
Stewart, June 4, 1983 6:28 pm, cleanup, add tunes and chirps in use stuff
Stewart, December 27, 1983 10:30 am, Cedar 5