<<>> <> <> <> <> <> <> <> <> <> <<$Tioga -- Sends a list of Tioga events (i.e., Tioga macros) to the Tioga input handler>> <<$Gargoyle>> <<$CommandTool>> <<$MessageWindow>> <<$Buttonizer>> <<$ButtonizerButtonizer>> <<>> DIRECTORY Atom, Commander, CommanderOps, Convert, EBTypes, EditedStream, EmbeddedButtons, Feedback, FeedbackOps, FeedbackTypes, FileNames, InputFocus, IO, List, Menus, MessageWindow, NodeProps, ProcessProps, PropRegistry, Rope, RuntimeError, SimpleFeedback, TEditDocument, TEditInput, TEditInputOps, TEditLocks, TEditOps, TEditSelection, TextEdit, TextNode, TiogaActive, TiogaOps, TypeScript, ViewerClasses, ViewerIO, ViewerTools; ButtonApplicationsImpl: CEDAR PROGRAM IMPORTS Atom, CommanderOps, Convert, EditedStream, EmbeddedButtons, Feedback, FeedbackOps, FileNames, InputFocus, IO, List, Menus, MessageWindow, NodeProps, ProcessProps, PropRegistry, Rope, RuntimeError, SimpleFeedback, TEditInput, TEditInputOps, TEditLocks, TEditOps, TEditSelection, TextEdit, TextNode, TiogaActive, TiogaOps, TypeScript, ViewerIO, ViewerTools = BEGIN ActiveButton: TYPE = EBTypes.ActiveButton; ActiveDoc: TYPE = EBTypes.ActiveDoc; ButtonInfo: TYPE = EBTypes.ButtonInfo; RegisteredNotifyProc: TYPE = EmbeddedButtons.RegisteredNotifyProc; ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; TiogaHandler: RegisteredNotifyProc = { <> < occurs, the named value is retrieved from the active document. This allows a button to base its operation on any of the values in the docuent.>> viewer: ViewerClasses.Viewer; inputFocus: InputFocus.Focus; events ¬ ProcessEvents[events, buttonInfo.doc]; <<>> inputFocus ¬ InputFocus.GetInputFocus[]; IF inputFocus # NIL THEN { viewer ¬ inputFocus.owner; IF viewer # NIL AND (viewer.class.flavor = $Text OR viewer.class.flavor = $Typescript) THEN { <> TiogaActive.Interpret[viewer, buttonInfo.button, buttonInfo.doc, events]; } ELSE SimpleFeedback.Append[routerName: $EmbeddedButtons, msgType: oneLiner, msgClass: $UserError, msg: "Tioga message handler: input focus not in a Tioga viewer."]; }; }; SyntaxError: PUBLIC SIGNAL[msg: Rope.ROPE] = CODE; ProcessEvents: PROC [events: LIST OF REF ANY, doc: ActiveDoc] RETURNS [newEvents: LIST OF REF ANY] = { z: LIST OF REF ANY; l: LIST OF REF ANY; newEvents ¬ LIST[NIL]; z ¬ newEvents; l ¬ events; DO IF l = NIL THEN EXIT; IF l.first # $EBApplications THEN { z.rest ¬ LIST[l.first]; z ¬ z.rest; l ¬ l.rest; } ELSE { l ¬ l.rest; IF l.first = $GetKeyValue THEN l ¬ GetKeyValue[l, doc] ELSE EmbeddedButtons.Error[Rope.Concat["Embedded buttons applications handler: Unknown function: ", Atom.GetPName[NARROW[l.first]]], Rope.Cat["The Embedded buttons applications handler encountered an unknown function following an $EBApplications atom: ", Atom.GetPName[NARROW[l.first]], ". The button press will be ignored."]]; }; ENDLOOP; newEvents ¬ newEvents.rest; }; GetKeyValue: PROC [l: LIST OF REF ANY, doc: ActiveDoc] RETURNS [newEvents: LIST OF REF ANY ¬ NIL] = { <> <<$GetKeyValue >> <<>> val: REF; key: ATOM; <> l ¬ l.rest; IF ~ISTYPE[l.first, ATOM] THEN {EmbeddedButtons.Error["Embedded buttons applications handler: Invalid key name in $GetKeyValue", "The Embedded buttons applications handler encountered an unknown object while expecting an ATOM. This occurred while processing a $EBApplications $GetKeyValue."]; RETURN;}; key ¬ NARROW[l.first]; <> val ¬ EmbeddedButtons.GetValue[key, doc]; newEvents ¬ LIST[val]; newEvents.rest ¬ l.rest; }; MessageWindowHandler: EmbeddedButtons.RegisteredNotifyProc = { <> PrintRef: PROC [item: REF] = { WITH item SELECT FROM atom: ATOM => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromAtom[atom]]; rope: Rope.ROPE => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromRope[rope]]; refInt: REF INT => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromInt[refInt­]]; refCard: REF CARD => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromCard[refCard­]]; refChar: REF CHAR => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromChar[refChar­]]; refBool: REF BOOL => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromBool[refBool­]]; l: LIST OF REF => { eventRope ¬ Rope.Concat[eventRope, "("]; IF l # NIL THEN { PrintRef[l.first]; FOR list: LIST OF REF ¬ l.rest, list.rest UNTIL list = NIL DO PrintRef[list.first]; ENDLOOP; }; eventRope ¬ Rope.Concat[eventRope, ")"]; }; ENDCASE => eventRope ¬ Rope.Concat[eventRope, " "]; }; eventRope: Rope.ROPE ¬ "Button sends event:"; FOR list: LIST OF REF ANY ¬ events, list.rest UNTIL list = NIL DO IF list.first = NIL THEN eventRope ¬ Rope.Concat[eventRope, " NIL"] ELSE PrintRef[list.first]; ENDLOOP; MessageWindow.Append[message: eventRope, clearFirst: TRUE]; }; TypescriptHandler: EmbeddedButtons.RegisteredNotifyProc = { <> <<>> eventRope: Rope.ROPE ¬ "Button sends event:"; FOR list: LIST OF REF ANY ¬ events, list.rest UNTIL list = NIL DO IF list.first = NIL THEN eventRope ¬ Rope.Concat[eventRope, " NIL"] ELSE WITH list.first SELECT FROM atom: ATOM => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromAtom[atom]]; rope: Rope.ROPE => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromRope[rope]]; refInt: REF INT => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromInt[refInt­]]; refCard: REF CARD => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromCard[refCard­]]; refChar: REF CHAR => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromChar[refChar­]]; refBool: REF BOOL => eventRope ¬ Rope.Cat[eventRope, " ", Convert.RopeFromBool[refBool­]]; ENDCASE => eventRope ¬ Rope.Concat[eventRope, " "]; ENDLOOP; SimpleFeedback.Append[routerName: $EmbeddedButtons, msgType: oneLiner, msgClass: $Typescript, msg: eventRope] }; commandsDir: ROPE ~ "/Cedar/Commands/"; tempDir: ROPE ~ "/tmp/"; defaultSearchRules: LIST OF REF ¬ LIST[commandsDir]; defaultPrompt: ROPE ¬ "%l%% %l"; -- from CommandToolImpl CommandToolHandler: EmbeddedButtons.RegisteredNotifyProc = { <> <> cmdr: Commander.Handle ¬ NEW[Commander.CommandObject]; out: Rope.ROPE; thisResult: REF; inner: PROC = { cmdr.in ¬ IO.noInputStream; cmdr.out ¬ cmdr.err ¬ FeedbackOps.GetTypescriptStream[$SystemScript]; IF cmdr.out = NIL THEN cmdr.out ¬ cmdr.err ¬ IO.noWhereStream; cmdr.propertyList ¬ LIST[ List.DotCons[key: $ErrorInputStream, val: IO.noInputStream], List.DotCons[key: $Prompt, val: defaultPrompt], List.DotCons[key: $WorkingDirectory, val: tempDir], -- needed? List.DotCons[key: $SearchRules, val: CONS[FileNames.HomeDirectory[], defaultSearchRules]]]; cmdr.procData ¬ NIL; FOR list: LIST OF REF ¬ events, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM commandLine: Rope.ROPE => { thisResult ¬ CommanderOps.DoCommand[commandLine, cmdr]; }; ENDCASE; ENDLOOP; IF thisResult = $Failure THEN result ¬ $Error ELSE result ¬ NIL; }; ProcessProps.AddPropList[ List.PutAssoc[key: $WorkingDirectory, val: tempDir, aList: NIL], inner]; <> }; ThisCommandToolHandler: EmbeddedButtons.RegisteredNotifyProc = { <> <> <> thisResult: REF; cmdr: Commander.Handle; WITH buttonInfo.doc.theDoc SELECT FROM v: ViewerClasses.Viewer => { <> IF TypeScript.IsATypeScript[v] THEN { menu: ViewerClasses.Menu ¬ v.menu; menuEntry: ViewerClasses.MenuEntry ¬ Menus.FindEntry[menu, "STOP!"]; clientData: REF; IF menuEntry = NIL THEN RETURN; clientData ¬ Menus.SetClientData[menuEntry, NIL]; [] ¬ Menus.SetClientData[menuEntry, clientData]; WITH clientData SELECT FROM cmd: Commander.Handle => cmdr ¬ cmd; ENDCASE => RETURN; } ELSE RETURN; }; ENDCASE => RETURN; FOR list: LIST OF REF ¬ events, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM commandLine: Rope.ROPE => { commandLine ¬ Rope.Concat[commandLine, "\n"]; SendCommand[commandLine, cmdr]; }; ENDCASE; ENDLOOP; IF thisResult = $Failure THEN result ¬ $Error ELSE result ¬ NIL; }; SendCommand: PROC [commandLine: ROPE, cmdr: Commander.Handle] = { <> viewer: ViewerClasses.Viewer; viewer ¬ TiogaOps.GetSelection[primary].viewer; WITH ViewerIO.GetViewerFromStream[cmdr.in] SELECT FROM v: ViewerClasses.Viewer => { bufferContents: REF TEXT ¬ ViewerIO.GetBuffer[cmdr.in]; IF bufferContents # NIL AND bufferContents.length > 0 AND bufferContents[bufferContents.length - 1] # '\n THEN { FOR n: NAT DECREASING IN [0..bufferContents.length) DO IF bufferContents[n] = '\n THEN { EditedStream.UnAppendBufferChars[ stream: cmdr.in, nChars: bufferContents.length - n - 1]; EXIT; } REPEAT FINISHED => EditedStream.UnAppendBufferChars[stream: cmdr.in, nChars: LAST[NAT]]; ENDLOOP; }; IF viewer = v THEN { <> ViewerTools.SetSelection[viewer: viewer, selection: NIL]; }; ViewerIO.TypeChars[editedViewerStream: cmdr.in, chars: commandLine]; }; ENDCASE => MessageWindow.Append["Bug in ButtonApplicationsImpl.SendCommand", TRUE] }; RopeConcat: EBTypes.EBLanguageProc = { <> <> rope: ROPE; FOR list: LIST OF REF ¬ arguments, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM r: ROPE => rope ¬ Rope.Concat[rope, r]; ENDCASE; ENDLOOP; RETURN[rope]; }; SelectionText: EBTypes.EBLanguageProc = { <> RETURN[ViewerTools.GetSelectionContents[]]; }; SelectionPropertyText: EBTypes.EBLanguageProc = { <> viewer: ViewerClasses.Viewer; start: TiogaOps.Location; key: ATOM; IF arguments = NIL THEN RETURN[NIL]; WITH arguments.first SELECT FROM a: ATOM => key ¬ a; r: ROPE => key ¬ Atom.MakeAtom[r]; ENDCASE => RETURN[NIL]; [viewer, start] ¬ TiogaOps.GetSelection[primary]; IF viewer # NIL AND NOT viewer.destroyed AND NOT viewer.newFile THEN { RETURN[TextEdit.GetCharProp[start.node, start.where, key]]; }; }; FileNameSelection: EBTypes.EBLanguageProc = { <> <> curSel: ROPE; viewer: ViewerClasses.Viewer; curSel ¬ ViewerTools.GetSelectionContents[]; curSel ¬ Rope.Substr[base: curSel, start: 0, len: curSel.Index[s2: "\n"]]; -- up to first CR IF (Rope.SkipTo[s: curSel, pos: 0, skip: " \t"] = curSel.Length[]) AND (curSel.Length[] > 1) THEN RETURN[curSel]; viewer ¬ TiogaOps.GetSelection[primary].viewer; IF viewer # NIL AND NOT viewer.destroyed AND NOT viewer.newFile THEN { fileName: ROPE ¬ viewer.file; fileName ¬ Rope.Substr[fileName, 0, Rope.SkipTo[fileName, 0, "!"]]; RETURN[fileName]; }; }; <<>> <> MakeCommanderButtonData: PROC RETURNS [buttonDataRope: Rope.ROPE, commandRope, firstWord: Rope.ROPE] = { commandRope ¬ ViewerTools.GetSelectionContents[]; firstWord ¬ IO.GetTokenRope[IO.RIS[commandRope]].token; buttonDataRope ¬ Rope.Cat["Poppy1\n", "Class: PopUpButton\n", IO.PutFR["Menu: (\n (\"%g\" \"%g\" \"%g\")\n )\n", [rope[Convert.RopeFromRope[commandRope, FALSE]]], [rope[firstWord]], [rope[Convert.RopeFromRope[commandRope, FALSE]]] ], "MessageHandler: CommandTool\n", "Feedback: (\n (MouseMoved )\n )" ]; }; ButtonDataFromSelection: PROC [handlerName: ROPE] RETURNS [buttonDataRope, commandRope: Rope.ROPE] = { commandRope ¬ ViewerTools.GetSelectionContents[]; buttonDataRope ¬ Rope.Cat["Poppy1\n", "Class: PopUpButton\n", IO.PutFLR["Menu: (\n ((%g) \"Do %g Command\" \"Send %g: %g\")\n )\n", LIST[[rope[commandRope]], [rope[handlerName]], [rope[handlerName]], [rope[Convert.RopeFromRope[commandRope, FALSE]]]] ], IO.PutFR1["MessageHandler: %g\n", [rope[handlerName]] ], "Feedback: (\n (MouseMoved )\n )" ]; }; Buttonize: EmbeddedButtons.RegisteredNotifyProc = { <> viewer: ViewerClasses.Viewer ¬ InputFocus.GetInputFocus[].owner; buttonDataRope: Rope.ROPE; <> rootOnly: BOOL ¬ FALSE; commandButtonizer: BOOL ¬ IF events = NIL THEN FALSE ELSE events.first = $Command; fromString: BOOL ¬ IF events = NIL THEN FALSE ELSE events.first = $FromString; IF fromString THEN { WITH events.rest.first SELECT FROM s: ROPE => { buttonDataRope ¬ s; Feedback.PutF[router, oneLiner, $Feedback, "Created button from string provided (%g ...)", [rope[Rope.Substr[buttonDataRope, 0, 30]]] ]; }; ENDCASE => { Feedback.Append[router, oneLiner, $Feedback, "FromString buttonizer couldn't find a string."]; RETURN; }; } ELSE IF commandButtonizer THEN { HandlerName: PROC [events: LIST OF REF] RETURNS [handlerName: ROPE] ~ { IF events = NIL OR events.rest = NIL THEN RETURN["Commander"] ELSE WITH events.rest.first SELECT FROM r: ROPE => RETURN[r]; a: ATOM => RETURN[Atom.GetPName[a]]; ENDCASE => RETURN["MessageWindow"]; -- as a sort of warning indicator }; handlerName: ROPE ¬ HandlerName[events]; IF Rope.Equal[handlerName, "Commander", FALSE] THEN { commandRope, firstWord: Rope.ROPE; [buttonDataRope, commandRope, firstWord] ¬ MakeCommanderButtonData[]; Feedback.PutFL[router, oneLiner, $Feedback, "Created Commander button (%g) (%g).", LIST[[rope[commandRope]], [rope[firstWord]]] ]; } ELSE { commandRope: Rope.ROPE; [buttonDataRope, commandRope] ¬ ButtonDataFromSelection[handlerName]; Feedback.PutFL[router, oneLiner, $Feedback, "Created %g button (%g).", LIST[[rope[handlerName]], [rope[commandRope]]] ]; }; } ELSE buttonDataRope ¬ EmbeddedButtons.GetRope[$ButtonDataLiteral, buttonInfo]; IF viewer.class.flavor = $Text OR viewer.class.flavor = $Typescript THEN { postfixRope: Rope.ROPE ¬ EmbeddedButtons.GetRope[$PostfixLiteral, buttonInfo]; IF buttonDataRope # NIL THEN SetProp[viewer, $ButtonData, buttonDataRope, rootOnly]; IF postfixRope # NIL THEN SetProp[viewer, $Postfix, postfixRope, rootOnly]; } ELSE IF viewer.class.flavor = $ActionArea AND buttonDataRope # NIL THEN { GGSetProp[viewer, $ButtonData, buttonDataRope, rootOnly]; }; }; ButtonizeButtonizer: EmbeddedButtons.RegisteredNotifyProc = { <> viewer: ViewerClasses.Viewer ¬ InputFocus.GetInputFocus[].owner; buttonDataRope: Rope.ROPE; <> rootOnly: BOOL ¬ FALSE; commanderButtonizer: BOOL ¬ IF events = NIL THEN FALSE ELSE events.first = $Command; result ¬ Buttonize[events, buttonInfo]; IF commanderButtonizer THEN { commandRope, firstWord: Rope.ROPE; [buttonDataRope, commandRope, firstWord] ¬ MakeCommanderButtonData[]; Feedback.PutFL[router, oneLiner, $Feedback, "Created command buttonizer (%g) (%g)", LIST[[rope[commandRope]], [rope[firstWord]]] ]; } ELSE { Feedback.Append[router, oneLiner, $Feedback, "Creating buttonizer from ButtonDataLiteral"]; buttonDataRope ¬ EmbeddedButtons.GetRope[$ButtonDataLiteral, buttonInfo]; }; IF viewer.class.flavor = $Text OR viewer.class.flavor = $Typescript THEN { postfixRope: Rope.ROPE ¬ EmbeddedButtons.GetRope[$PostfixLiteral, buttonInfo]; IF buttonDataRope # NIL THEN SetProp[viewer, $ButtonDataLiteral, buttonDataRope, rootOnly]; IF postfixRope # NIL THEN SetProp[viewer, $PostfixLiteral, postfixRope, rootOnly]; } ELSE IF viewer.class.flavor = $ActionArea AND buttonDataRope # NIL THEN { GGSetProp[viewer, $ButtonDataLiteral, buttonDataRope, rootOnly]; }; }; UnButtonize: EmbeddedButtons.RegisteredNotifyProc = { <> <<>> viewer: ViewerClasses.Viewer ¬ InputFocus.GetInputFocus[].owner; rootOnly: BOOL ¬ IF events = NIL THEN FALSE ELSE events.first = $Root; IF viewer.class.flavor = $Text OR viewer.class.flavor = $Typescript THEN { RemProp[viewer, $ButtonData, rootOnly]; RemProp[viewer, $ButtonFeedback, rootOnly]; RemProp[viewer, $ButtonTarget, rootOnly]; RemProp[viewer, $Postfix, rootOnly]; } ELSE IF viewer.class.flavor = $ActionArea THEN { GGRemProp[viewer, $ButtonData, rootOnly]; GGRemProp[viewer, $ButtonFeedback, rootOnly]; GGRemProp[viewer, $ButtonTarget, rootOnly]; }; }; SetProp: PROC [viewer: Viewer, key: ATOM, valueRope: Rope.ROPE, rootOnly: BOOL] = { Put: PROC [node: TextNode.Ref, start, size: INT] = { value: REF ~ NodeProps.DoSpecs[key, valueRope]; TextEdit.PutCharProp[node: node, index: start, name: key, value: value, nChars: size, event: TEditInput.CurrentEvent[], root: root] }; pSel: TEditDocument.Selection; root: TextNode.Ref; TEditSelection.LockSel[primary, "ButtonizerImpl.SetProp"]; pSel ¬ TEditOps.GetSelData[]; IF NOT TEditInputOps.CheckReadonly[pSel] THEN { TEditSelection.UnlockSel[primary]; RETURN; }; root ¬ TEditSelection.SelectionRoot[pSel]; [] ¬ TEditLocks.Lock[root, "ButtonizerImpl.SetProp"]; ForEachNode[pSel, Put ! RuntimeError.UNCAUGHT => { MessageWindow.Append["Uncaught error in ButtonizerImpl.SetProp", TRUE]; MessageWindow.Blink[]; CONTINUE; }; ]; TEditSelection.UnlockDocAndPSel[root]; }; RemProp: PROC [viewer: Viewer, key: ATOM, rootOnly: BOOL] = { Rem: PROC [node: TextNode.Ref, start, size: INT] = { TextEdit.PutCharProp[node: node, index: start, name: key, value: NIL, nChars: size, event: TEditInput.CurrentEvent[], root: root] }; pSel: TEditDocument.Selection; root: TextNode.Ref; TEditSelection.LockSel[primary, "ButtonizerImpl.RemProp"]; pSel ¬ TEditOps.GetSelData[]; IF NOT TEditInputOps.CheckReadonly[pSel] THEN { TEditSelection.UnlockSel[primary]; RETURN; }; root ¬ TEditSelection.SelectionRoot[pSel]; [] ¬ TEditLocks.Lock[root, "ButtonizerImpl.RemProp"]; ForEachNode[pSel, Rem ! RuntimeError.UNCAUGHT => { MessageWindow.Append["Uncaught error in ButtonizerImpl.RemProp", TRUE]; MessageWindow.Blink[]; CONTINUE; }; ]; TEditSelection.UnlockDocAndPSel[root]; }; <> <> <> <<};>> <<>> GGSetProp: PROC [viewer: Viewer, key: ATOM, valueRope: Rope.ROPE, rootOnly: BOOL] = { propClass: PropRegistry.RegistryClass; setProp: PropRegistry.PropSetProc; propClass ¬ PropRegistry.GetRegistered[$ActionArea]; IF propClass = NIL THEN RETURN; setProp ¬ propClass.setProp; IF setProp # NIL THEN setProp[key: key, doc: viewer, hint: NIL, prop: valueRope, edited: TRUE]; }; <> <> <> <<};>> <<>> GGRemProp: PROC [viewer: Viewer, key: ATOM, rootOnly: BOOL] = { propClass: PropRegistry.RegistryClass; remProp: PropRegistry.PropRemProc; propClass ¬ PropRegistry.GetRegistered[$ActionArea]; IF propClass = NIL THEN RETURN; remProp ¬ propClass.remProp; IF remProp # NIL THEN remProp[key: key, doc: viewer, hint: NIL, edited: TRUE]; }; ForEachNode: PROC [pSel: TEditDocument.Selection, proc: PROC [node: TextNode.Ref, start: INT, size: INT]] = { FOR node: TextNode.Ref ¬ pSel.start.pos.node, TextNode.StepForward[node] DO start: INT ¬ 0; end: INT ¬ TextEdit.Size[node]; IF node = pSel.start.pos.node AND pSel.start.pos.where # TextNode.NodeItself THEN { start ¬ pSel.start.pos.where; }; IF node = pSel.end.pos.node AND pSel.end.pos.where # TextNode.NodeItself THEN { end ¬ MIN[end, pSel.end.pos.where+1]; }; proc[node: node, start: start, size: end-start]; IF node = pSel.end.pos.node THEN EXIT; ENDLOOP; }; <<>> <> <<>> router: FeedbackTypes.MsgRouter ¬ Feedback.EnsureRouter[$EmbeddedButtons]; FeedbackOps.SetMultiTypescript[router, $SystemScript, LIST[$SyntaxError, $InternalError, $Typescript, $UserError, $Feedback]]; FeedbackOps.SetMultiMessageWindow[router, TRUE, LIST[$UserError]]; FeedbackOps.SetMultiMessageWindow[router, FALSE, LIST[$Screen, $Feedback]]; EmbeddedButtons.RegisterApplication[$Tioga, TiogaHandler]; EmbeddedButtons.RegisterApplication[$MessageWindow, MessageWindowHandler]; EmbeddedButtons.RegisterApplication[$Typescript, TypescriptHandler]; EmbeddedButtons.RegisterApplication[$CommandTool, CommandToolHandler]; EmbeddedButtons.RegisterApplication[$ThisCommandTool, ThisCommandToolHandler]; EmbeddedButtons.RegisterApplication[$Buttonizer, Buttonize]; EmbeddedButtons.RegisterApplication[$ButtonizerButtonizer, ButtonizeButtonizer]; EmbeddedButtons.RegisterApplication[$UnButtonizer, UnButtonize]; EmbeddedButtons.RegisterPoppyProc[$Concat, RopeConcat]; EmbeddedButtons.RegisterPoppyProc[$SelectionText, SelectionText]; EmbeddedButtons.RegisterPoppyProc[$SelectionPropertyText, SelectionPropertyText]; <> EmbeddedButtons.RegisterPoppyProc[$CurrentSelection, SelectionText]; EmbeddedButtons.RegisterPoppyProc[$FileNameSelection, FileNameSelection]; END.