DIRECTORY Args USING [Arg, ArgsGet, Error], Buttons USING [Button, ButtonProc, Create, SetDisplayStyle], ChoiceButtons USING [BuildEnumTypeSelection, ChoiceDoesntExist, GetSelectedButton, EnumTypeRef, UpdateChoiceButtons], Commander USING [CommandProc, Register], Containers USING [Create], Convert USING [Error, IntFromRope, RopeFromInt, RealFromRope, RopeFromReal], FileDWIM USING [ResolveHint], Icons USING [IconFlavor, NewIconFromFile], IO, IPMaster USING [Version], Labels USING [Create, Set, SetDisplayStyle], Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuEntry, MenuProc], PieViewers USING [Create, Set], PFS USING [Error], PrintingP4V3Aux USING [ExposeFormatterStatus, ExposeInterpressMasterStatus, ExposeMarkingEngineStatus, ExposeSpoolerStatus], Process USING [Detach, SecondsToTicks, SetTimeout], Rope, RopeList USING [Memb, Reverse], Rules USING [Create], SymTab USING [Create, Fetch, Ref, Store], TypeScript USING [Create], UserProfile USING [Boolean, CallWhenProfileChanges, ListOfTokens, ProfileChangedProc, Token], ViewerClasses USING [AdjustProc, Viewer, ViewerClass, ViewerClassRec, ViewerRec], ViewerIO USING [CreateMessageWindowStream, CreateViewerStreams], ViewerLocks USING [CallUnderWriteLock], ViewerOps USING [AddProp, CreateViewer, DestroyViewer, EnumProc, EnumerateViewers, EstablishViewerPosition, FetchProp, MoveViewer, PaintHint, PaintViewer, RegisterViewerClass, SetMenu], ViewerTools USING [GetContents, GetSelectedViewer, GetSelectionContents, InhibitUserEdits, MakeNewTextViewer, SetContents, SetSelection], VFonts USING [CharWidth, StringWidth], WindowManager USING [colorDisplayOn], XNSCredentials USING [XNSCredentialsChangeProc, RegisterForChange], XNSPrint USING [Context, Error, GetDefaults, GetPrinterProperties, GetPrinterStatus, Properties, PrinterStatus, PrintRequest, RequestStatus, StatusChangedProc, UnRegisterPrintRequest], XTSetter, XTSetterPrivate; XTSetterImpl: CEDAR MONITOR LOCKS tool USING tool: Tool IMPORTS Args, Buttons, ChoiceButtons, Commander, Containers, Convert, FileDWIM, Icons, IO, Labels, Menus, PFS, PieViewers, PrintingP4V3Aux, Process, Rope, RopeList, Rules, SymTab, TypeScript, UserProfile, ViewerIO, ViewerLocks, ViewerOps, ViewerTools, VFonts, WindowManager, XNSCredentials, XNSPrint, XTSetter EXPORTS XTSetter, XTSetterPrivate ~ BEGIN OPEN XTSetterPrivate, PrintingAux: PrintingP4V3Aux; ToolRep: PUBLIC TYPE ~ XTSetterPrivate.ToolRep; ViewerRanking: TYPE ~ {serverStatus, options, statusContainer, statusRule, typeScript}; xTSViewerIcon: Icons.IconFlavor; -- XTSetter icon xTSViewerClass: ViewerClasses.ViewerClass; -- XTSetter viewer class defaultOptions: Options; -- default set of options, not including those derived from default XNSPrint context styleList: LIST OF ROPE; -- list of styles to be suggested to the user deviceList: LIST OF ROPE; -- list of devices to be suggested to the user printerVersions: SymTab.Ref; -- printer name -> version ropeToVersion: SymTab.Ref; -- maps 3.0-PGS to version standardVersions: LIST OF ROPE ฌ LIST [ -- versions for usual printers "Quoth", "3.0-PGS", "Quill", "3.0-PGS", "TimsPrinter", "3.0-PGS", "Zipper", "3.0-CS", "Perfector", "2.1-RLS", "Scripto", "1.0", "Papermate", "1.0"]; Error: PUBLIC ERROR [why: ROPE] = CODE; GetTool: PUBLIC PROC [printer: ROPE ฌ NIL, new: BOOL ฌ FALSE] RETURNS [tool: Tool ฌ NIL] ~ { LookUpTool: ViewerOps.EnumProc ~ { IF v.class#xTSViewerClass OR v.destroyed OR ~Rope.Equal[v.name, printer] THEN RETURN [TRUE]; tool ฌ NARROW [v.data]; RETURN [FALSE]; }; IF Rope.IsEmpty[printer] THEN printer ฌ XNSPrint.GetDefaults[].printerName; IF ~new THEN ViewerOps.EnumerateViewers[LookUpTool]; -- search a candidate tool IF tool=NIL THEN tool ฌ NewTool[printer, ViewerIO.CreateMessageWindowStream[]]; }; NewTool: PROC [printer: ROPE, feedBack: STREAM] RETURNS [tool: Tool] ~ { ENABLE XNSPrint.Error => { feedBack.PutF["Unable to connect to printer %g: %g\n", IO.rope[printer], IO.rope[explanation]]; IO.Flush[feedBack]; ERROR Error[why: explanation]; }; tool ฌ NEW [ToolRep ฌ [printerName: printer]]; tool.printerProperties ฌ XNSPrint.GetPrinterProperties[tool.printerName].answer; SetupPrinterVersion[tool]; tool.currentOptions ฌ DefaultOptions[]; tool.currentOptions.compress ฌ tool.version.shouldCompress; CreateViewer[tool]; -- Create all the viewer structure and display it tool.feedBack.PutF1["Connection with %g established.\n", IO.rope[tool.printerName]]; }; CreateViewer: PROC [tool: Tool] ~ { AddMenuEntry: PROCEDURE [name: ROPE, proc: Menus.MenuProc, fork: BOOL ฌ FALSE, row: INTEGER ฌ 0, guardDoc: ROPE ฌ NIL] = { menuEntry: Menus.MenuEntry = Menus.CreateEntry[name: name, proc: proc, clientData: tool, documentation: guardDoc, fork: fork, guarded: guardDoc#NIL]; Menus.AppendMenuEntry[menu, menuEntry, row]; }; menu: Menus.Menu = Menus.CreateMenu[]; typeScript: Viewer; tool.viewer ฌ ViewerOps.CreateViewer[flavor: $XTSetter, info: [name: tool.printerName, label: GetLabel[tool], column: right, scrollable: FALSE, data: tool], paint: FALSE -- We'll paint it after it has been built ]; AddMenuEntry[name: "New", proc: NewButton, fork: TRUE]; AddMenuEntry[name: "<--", proc: LeftScreenButton]; AddMenuEntry[name: "Screen", proc: ScreenButton]; AddMenuEntry[name: "-->", proc: RightScreenButton]; AddMenuEntry[name: "Color", proc: ColorScreenButton]; AddMenuEntry[name: "Print", proc: PrintButton, fork: TRUE]; AddMenuEntry[name: "Options", proc: OptionsButton, fork: TRUE]; AddMenuEntry[name: "ServerStatus", proc: ServerStatusButton, fork: TRUE]; ViewerOps.SetMenu[tool.viewer, menu]; typeScript ฌ TypeScript.Create[ info: [parent: tool.viewer, wx: 0, wy: 0, ww: 9999, wh: 0, border: FALSE], paint: FALSE]; ViewerTools.InhibitUserEdits[typeScript]; PlaceChild[viewer: typeScript, rank: typeScript, minSize: 30, maxSize: -1]; tool.feedBack ฌ ViewerIO.CreateViewerStreams[name: NIL, viewer: typeScript].out; ViewerOps.PaintViewer[tool.viewer, all]; }; GetLabel: PROC [tool: Tool] RETURNS [label: ROPE] ~ { name: ROPE ฌ tool.printerName; RETURN[ name.Substr[0, name.Index[s2:":"]] ]; }; DestroyTool: PUBLIC ENTRY PROC [tool: Tool] ~ { ENABLE UNWIND => NULL; ViewerOps.DestroyViewer[tool.viewer]; }; NewButton: Menus.MenuProc ~ { tool: Tool = NARROW[clientData]; printer: ROPE = ViewerTools.GetSelectionContents[]; IF ~Rope.IsEmpty[printer] THEN [] ฌ NewTool[printer, tool.feedBack ! Error => CONTINUE]; }; LeftScreenButton: Menus.MenuProc ~ { tool: Tool = NARROW[clientData]; XTSetter.PrintScreen[tool, left]; }; ScreenButton: Menus.MenuProc ~ { tool: Tool = NARROW[clientData]; XTSetter.PrintScreen[tool, bw]; }; RightScreenButton: Menus.MenuProc ~ { tool: Tool = NARROW[clientData]; XTSetter.PrintScreen[tool, right]; }; ColorScreenButton: Menus.MenuProc ~ { tool: Tool = NARROW[clientData]; IF WindowManager.colorDisplayOn THEN XTSetter.PrintScreen[tool, color] ELSE tool.feedBack.PutRope["Color display is off! Nothing to print...\n"]; }; PrintButton: Menus.MenuProc ~ { FileNameSelected: PROC [self: ROPE] RETURNS [BOOL] ~ { length: INT = self.Length[]; IF length < 2 THEN RETURN [FALSE]; -- rope is too short IF Rope.SkipTo[s: self, skip: " \t"] # length THEN RETURN [FALSE]; -- whitespace in rope RETURN [TRUE]; -- All is OK }; FileFromHint: PROC [hint: ROPE, v: Viewer] RETURNS [fName: ROPE] ~ { ENABLE PFS.Error => GO TO Failed; ctxFN: ROPE; IF v=NIL THEN RETURN [fName: hint]; -- no hope... ctxFN ฌ v.file; IF Rope.IsEmpty[ctxFN] AND v.name#NIL THEN { -- hack for CommandTool wDir ctxFN ฌ Rope.Substr[v.name, 0, Rope.SkipTo[v.name, 0, " "]]; ctxFN ฌ XTSetter.ExpandName["Dummy.dummy", ctxFN].fullFName; }; fName ฌ FileDWIM.ResolveHint[hint: hint, contextFileName: ctxFN, searchHack: FALSE, tryAll: TRUE].fullFileName; IF Rope.IsEmpty[fName] THEN fName ฌ hint; EXITS Failed => fName ฌ hint; }; InvalidFile: PROC [why: ROPE] ~ { IO.PutF1[tool.feedBack, "File error: %g\n", IO.rope[why]]; }; tool: Tool = NARROW[clientData]; curSel: ROPE = ViewerTools.GetSelectionContents[]; curViewer: Viewer = ViewerTools.GetSelectedViewer[]; SELECT TRUE FROM FileNameSelected[curSel] => { -- Print the file name selected fName: ROPE = FileFromHint[curSel, curViewer]; XTSetter.PrintFile[tool, fName ! PFS.Error => { InvalidFile[error.explanation]; GOTO Failed }]; }; curViewer#NIL => { -- Print a viewer XTSetter.PrintViewer[tool, curViewer]; }; ENDCASE => { -- No way to print anything IO.PutRope[tool.feedBack, "Nothing to print has been selected!\n"]; }; EXITS Failed => NULL; }; OptionsButton: Menus.MenuProc ~ { tool: Tool = NARROW[clientData]; IF tool.optionsViewer=NIL OR tool.optionsViewer.destroyed THEN CreateOptionsViewer[tool] ELSE DestroyOptionsViewer[tool]; }; ServerStatusButton: Menus.MenuProc ~ { tool: Tool = NARROW[clientData]; IF tool.printerStatusViewer=NIL OR tool.printerStatusViewer.destroyed THEN CreateServerStatusViewer[tool] ELSE DestroyServerStatusViewer[tool]; }; Pos: TYPE ~ RECORD [x, y: INT]; entryHSpace: INT ฌ 6; entryVSpace: INT ฌ 16; textFuzz: INT ฌ 1; CreateBoolButton: PROC [name: ROPE, parent: Viewer, pos: Pos, init, possible: BOOL, click: BoolButtonActionProc ฌ NIL] RETURNS [state: BoolButton, newx: INT] ~ { state ฌ NEW [BoolButtonRep ฌ [NIL, FALSE, IF possible THEN $WhiteOnBlack ELSE $BlackOnGrey, click]]; state.buttonฌ Buttons.Create[ info: [name: name, wx: pos.x, wy: pos.y, parent: parent, border: TRUE], proc: ClickBoolButton, fork: FALSE, paint: FALSE, clientData: state ]; newx ฌ pos.x + state.button.ww + entryHSpace; SetBoolButton[state, init AND possible]; }; ClickBoolButton: Buttons.ButtonProc ~ { state: BoolButton = NARROW [clientData]; SetBoolButton[state, NOT state.flag]; IF state.click#NIL THEN state.click[state]; }; GetBoolButton: PROC [state: BoolButton] RETURNS [BOOL] ~ { RETURN [state.flag]; }; SetBoolButton: PROC [state: BoolButton, value: BOOL]~ { state.flag ฌ value; Buttons.SetDisplayStyle[state.button, IF value THEN state.trueStyle ELSE $BlackOnWhite]; }; CreateIntButton: PROC [name: ROPE, parent: Viewer, pos: Pos, w: INT ฌ 9999, default: INT, defined: BOOL ฌ TRUE, init: INT ฌ 0] RETURNS [state: IntButton, newx: INT] ~ { state ฌ NEW [IntButtonRep ฌ [default: default]]; state.button ฌ Buttons.Create[ info: [name: name, wx: pos.x, wy: pos.y, parent: parent, border: FALSE], proc: ClickIntButton, fork: FALSE, clientData: state, paint: FALSE ]; pos ฌ [pos.x + state.button.ww, pos.y+textFuzz]; -- adjust text viewer to button!!! state.text ฌ ViewerTools.MakeNewTextViewer[ info: [parent: parent, wx: pos.x, wy: pos.y, ww: w, wh: state.button.wh, border: FALSE], paint: FALSE]; newx ฌ pos.x + w; SetIntButton[state, defined, init]; }; GetIntButton: PROC [state: IntButton] RETURNS [val: INT] ~ { val ฌ state.default; val ฌ Convert.IntFromRope[ViewerTools.GetContents[state.text] ! Convert.Error => CONTINUE]; }; SetIntButton: PROC [state: IntButton, defined: BOOL ฌ TRUE, init: INT ฌ 0] ~ { val: ROPE ฌ NIL; IF defined AND init#state.default THEN val ฌ Convert.RopeFromInt[init]; ViewerTools.SetContents[state.text, val]; }; ClickIntButton: Buttons.ButtonProc ~ { state: IntButton = NARROW [clientData]; ViewerTools.SetSelection[state.text]; }; CreateRealButton: PROC [name: ROPE, parent: Viewer, pos: Pos, w: INT ฌ 9999, default: REAL, defined: BOOL ฌ TRUE, init: REAL ฌ 0.0] RETURNS [state: RealButton, newx: INT] ~ { state ฌ NEW [RealButtonRep ฌ [default: default]]; state.button ฌ Buttons.Create[ info: [name: name, wx: pos.x, wy: pos.y, parent: parent, border: FALSE], proc: ClickRealButton, fork: FALSE, clientData: state, paint: FALSE ]; pos ฌ [pos.x + state.button.ww, pos.y+textFuzz]; -- adjust text viewer to button!!! state.text ฌ ViewerTools.MakeNewTextViewer[ info: [parent: parent, wx: pos.x, wy: pos.y, ww: w, wh: state.button.wh, border: FALSE], paint: FALSE]; newx ฌ pos.x + w; SetRealButton[state, defined, init]; }; GetRealButton: PROC [state: RealButton] RETURNS [val: REAL] ~ { val ฌ state.default; val ฌ Convert.RealFromRope[ViewerTools.GetContents[state.text] ! Convert.Error => CONTINUE]; }; SetRealButton: PROC [state: RealButton, defined: BOOL ฌ TRUE, init: REAL ฌ 0] ~ { val: ROPE ฌ NIL; IF defined AND init#state.default THEN val ฌ Convert.RopeFromReal[init]; ViewerTools.SetContents[state.text, val]; }; ClickRealButton: Buttons.ButtonProc ~ { state: RealButton = NARROW [clientData]; ViewerTools.SetSelection[state.text]; }; CreateRopeButton: PROC [name: ROPE, parent: Viewer, pos: Pos, w: INT ฌ 9999, values: LIST OF ROPE ฌ NIL, init: ROPE ฌ NIL] RETURNS [state: RopeButton, newx: INT] ~ { state ฌ NEW [RopeButtonRep ฌ [defaults: values]]; state.button ฌ Buttons.Create[ info: [name: name, wx: pos.x, wy: pos.y, parent: parent, border: FALSE], proc: ClickRopeButton, fork: FALSE, clientData: state, paint: FALSE ]; pos ฌ [pos.x + state.button.ww, pos.y+textFuzz]; -- adjust text viewer to button!!! state.text ฌ ViewerTools.MakeNewTextViewer[ info: [parent: parent, wx: pos.x, wy: pos.y, ww: w, wh: state.button.wh, border: FALSE], paint: FALSE]; newx ฌ pos.x + w + entryHSpace; SetRopeButton[state, init]; }; GetRopeButton: PROC [state: RopeButton] RETURNS [ROPE] ~ { RETURN [ViewerTools.GetContents[state.text]]; }; SetRopeButton: PROC [state: RopeButton, val: ROPE] ~ { ViewerTools.SetContents[state.text, val]; }; ClickRopeButton: Buttons.ButtonProc ~ { NextName: PROC [state: RopeButton] RETURNS [next: ROPE ฌ NIL] = { current: ROPE = ViewerTools.GetContents[state.text]; IF state.defaults = NIL THEN RETURN; FOR l: LIST OF ROPE ฌ state.defaults, l.rest UNTIL l = NIL DO IF current.Equal[l.first, FALSE] THEN RETURN[IF l.rest = NIL THEN state.defaults.first ELSE l.rest.first]; ENDLOOP; RETURN[state.defaults.first] }; state: RopeButton = NARROW [clientData]; IF mouseButton = blue THEN ViewerTools.SetSelection[state.text] ELSE ViewerTools.SetContents[state.text, NextName[state]]; }; ClickCompress: BoolButtonActionProc ~ { tool: Tool ฌ NARROW [state.button.parent.parent.data]; }; CreateOptionsViewer: PUBLIC ENTRY PROC [tool: Tool] ~ { ENABLE UNWIND => NULL; curPos: Pos; em: INT = VFonts.CharWidth['m]; options: Options ฌ tool.currentOptions; paperButtons: LIST OF ROPE ฌ NIL; -- the list of buttons to select paper defaultPaper: ROPE; -- the default thereof IF ~NoViewer[tool.optionsViewer] THEN RETURN; -- Just being paranoid tool.optionsViewer ฌ Containers.Create[ info: [parent: tool.viewer, scrollable: FALSE, wx: 0, wy: 0, ww: 9999, wh: 0, border: FALSE], paint: FALSE]; curPos ฌ [entryHSpace, 4]; IF tool.version.mayCompress THEN [tool.optionsCompress, curPos.x] ฌ CreateBoolButton[name: "Compress", parent: tool.optionsViewer, pos: curPos, init: options.compress, possible: TRUE, click: ClickCompress]; [tool.optionsKeepIP, curPos.x] ฌ CreateBoolButton[name: "KeepIP", parent: tool.optionsViewer, pos: curPos, init: options.keepIP, possible: TRUE]; [tool.optionsScale, curPos.x] ฌ CreateRealButton[name: "Scale:", parent: tool.optionsViewer, pos: curPos, w: 6*em, default: 1.0, init: options.tiogaScale]; [tool.optionsStyle, curPos.x] ฌ CreateRopeButton[name: "Style:", parent: tool.optionsViewer, pos: curPos, values: styleList, init: options.tiogaStyle]; curPos ฌ [entryHSpace, curPos.y + entryVSpace]; [tool.optionsStaple, curPos.x] ฌ CreateBoolButton[name: "Staple", parent: tool.optionsViewer, pos: curPos, init: options.stapled, possible: tool.printerProperties.staple]; [tool.optionsTwoSided, curPos.x] ฌ CreateBoolButton[name: "2-sided", parent: tool.optionsViewer, pos: curPos, init: options.twoSided, possible: tool.printerProperties.twoSided]; [tool.optionsCopies, curPos.x] ฌ CreateIntButton[name: "Copies:", parent: tool.optionsViewer, pos: curPos, w: 4*em, default: 1, init: options.copyCount]; [tool.optionsFirstpage, curPos.x] ฌ CreateIntButton[name: "Page:", parent: tool.optionsViewer, pos: curPos, w: 7*em, default: 1, init: options.pageFirst]; [tool.optionsLastpage, curPos.x] ฌ CreateIntButton[name: "To:", parent: tool.optionsViewer, pos: curPos, w: 7*em, default: LAST [CARD16], init: options.pageLast]; curPos ฌ [entryHSpace, curPos.y + entryVSpace]; FOR mList: LIST OF ROPE ฌ tool.printerProperties.media, mList.rest WHILE mList#NIL DO IF Rope.Equal[mList.first, options.mediumHint] THEN defaultPaper ฌ mList.first; IF NOT RopeList.Memb[paperButtons, mList.first] THEN paperButtons ฌ CONS [mList.first, paperButtons]; ENDLOOP; paperButtons ฌ RopeList.Reverse[paperButtons]; IF Rope.IsEmpty[defaultPaper] THEN defaultPaper ฌ paperButtons.first; -- valid default tool.optionsPaper ฌ ChoiceButtons.BuildEnumTypeSelection[ title: "Paper:", style: menuSelection, viewer: tool.optionsViewer, x: curPos.x, y: curPos.y, buttonNames: paperButtons, default: defaultPaper]; curPos ฌ [entryHSpace, curPos.y + entryVSpace]; [tool.optionsDevice, curPos.x] ฌ CreateRopeButton[name: "Device:", parent: tool.optionsViewer, pos: curPos, values: deviceList, init: options.device]; [] ฌ Rules.Create[ info: [parent: tool.optionsViewer, wx: 0, wy: curPos.y+entryVSpace, ww: 9999, wh: 1], paint: FALSE]; PlaceChild[viewer: tool.optionsViewer, rank: options, minSize: curPos.y+entryVSpace+1, maxSize: curPos.y+entryVSpace+1]; [] ฌ RedisplayTool[tool]; }; DestroyOptionsViewer: PUBLIC ENTRY PROC [tool: Tool] ~ { ENABLE UNWIND => NULL; [] ฌ GetOptionsInternal[tool, FALSE]; ViewerOps.DestroyViewer[viewer: tool.optionsViewer, paint: FALSE]; tool.optionsViewer ฌ NIL; [] ฌ RedisplayTool[tool]; }; GetOptions: PUBLIC ENTRY PROC [tool: Tool, reset: BOOL ฌ TRUE] RETURNS [options: Options] ~ { ENABLE UNWIND => NULL; options ฌ GetOptionsInternal[tool, reset]; }; GetOptionsInternal: PUBLIC PROC [tool: Tool, reset: BOOL ฌ TRUE] RETURNS [options: Options] ~ { IF ~NoViewer[tool.optionsViewer] THEN { -- Actualize options from viewer if present tool.currentOptions.compress ฌ IF tool.optionsCompress#NIL THEN GetBoolButton[state: tool.optionsCompress] ELSE FALSE; tool.currentOptions.keepIP ฌ GetBoolButton[state: tool.optionsKeepIP]; tool.currentOptions.copyCount ฌ GetIntButton[state: tool.optionsCopies]; tool.currentOptions.pageFirst ฌ GetIntButton[state: tool.optionsFirstpage]; tool.currentOptions.pageLast ฌ GetIntButton[state: tool.optionsLastpage]; tool.currentOptions.mediumHint ฌ ChoiceButtons.GetSelectedButton[tool.optionsPaper]; tool.currentOptions.stapled ฌ GetBoolButton[state: tool.optionsStaple]; tool.currentOptions.twoSided ฌ GetBoolButton[state: tool.optionsTwoSided]; tool.currentOptions.telephone ฌ NIL; -- Not yet defined tool.currentOptions.tiogaStyle ฌ GetRopeButton[state: tool.optionsStyle]; tool.currentOptions.device ฌ GetRopeButton[state: tool.optionsDevice]; tool.currentOptions.tiogaScale ฌ GetRealButton[state: tool.optionsScale]; IF reset THEN { -- Reset volatile options in viewer to their defaults SetIntButton[state: tool.optionsCopies, defined: FALSE]; SetIntButton[state: tool.optionsFirstpage, defined: FALSE]; SetIntButton[state: tool.optionsLastpage, defined: FALSE]; SetRealButton[state: tool.optionsScale, defined: FALSE]; }; }; options ฌ NEW [OptionsRep ฌ tool.currentOptionsญ]; -- return copy of tool options }; SetOptions: PUBLIC ENTRY PROC [tool: Tool, options: Options] ~ { ENABLE UNWIND => NULL; tool.currentOptionsญ ฌ optionsญ; -- copy all options into tool IF ~NoViewer[tool.optionsViewer] THEN { -- Actualize options to viewer if present IF tool.optionsCompress#NIL THEN { SetBoolButton[state: tool.optionsCompress, value: options.compress]; ClickCompress[tool.optionsCompress]; }; SetBoolButton[state: tool.optionsKeepIP, value: options.keepIP]; SetBoolButton[state: tool.optionsStaple, value: options.stapled]; SetBoolButton[state: tool.optionsTwoSided, value: options.twoSided]; SetIntButton[state: tool.optionsCopies, init: options.copyCount]; SetIntButton[state: tool.optionsFirstpage, init: options.pageFirst]; SetIntButton[state: tool.optionsLastpage, init: options.pageLast]; ChoiceButtons.UpdateChoiceButtons[viewer: tool.optionsViewer, enumTypeInfo: tool.optionsPaper, newName: options.mediumHint ! ChoiceButtons.ChoiceDoesntExist => CONTINUE]; SetRopeButton[state: tool.optionsStyle, val: options.tiogaStyle]; SetRealButton[state: tool.optionsScale, init: options.tiogaScale]; SetRopeButton[state: tool.optionsDevice, val: options.device]; }; }; DefaultOptions: PUBLIC PROC [] RETURNS [options: Options] ~ { context: XNSPrint.Context ฌ XNSPrint.GetDefaults[]; options ฌ NEW [OptionsRep ฌ defaultOptionsญ]; -- maintained through user profile options.mediumHint ฌ context.mediumHint; options.stapled ฌ context.stapled; options.twoSided ฌ context.twoSided; options.telephone ฌ context.telephone; }; DefaultOptionsFromProfile: PROC [] ~ { EachTool: ViewerOps.EnumProc ~ { tool: Tool; IF v.class#xTSViewerClass OR v.destroyed THEN RETURN [TRUE]; tool ฌ NARROW [v.data]; SetupPrinterVersion[tool]; }; options: Options ฌ NEW [OptionsRep]; options.keepIP ฌ UserProfile.Boolean["XTSetter.KeepIP", FALSE]; options.tiogaStyle ฌ UserProfile.Token["XTSetter.Style", NIL]; options.device ฌ UserProfile.Token["XTSetter.Device", IF UserProfile.Boolean["XTSetter.UsePressFonts", FALSE] THEN "press" ELSE NIL]; defaultOptions ฌ options; styleList ฌ UserProfile.ListOfTokens["XTSetter.StyleList", LIST ["Slides", "TwoColumnLandscapeCedar", "TwoColumnCedar", "AnacapaCedar", "AnacapaSlides", "BlueAndWhite", "CedarACM", "33UpLabels"]]; deviceList ฌ UserProfile.ListOfTokens["XTSetter.DeviceList", LIST ["press", "xcc", "anacapa"]]; DefinePrinterVersions[standardVersions]; DefinePrinterVersions[UserProfile.ListOfTokens["XTSetter.PrinterVersions", NIL]]; ViewerOps.EnumerateViewers[EachTool]; -- recompute correct IP version for existing tools }; CreateServerStatusViewer: PUBLIC ENTRY PROC [tool: Tool] ~ { ENABLE UNWIND => NULL; NewNamedLabel: PROC [name: ROPE, size: ROPE ฌ NIL, w: INT ฌ 0] RETURNS [v: Viewer] ~ { width: INT = IF Rope.IsEmpty[size] THEN w ELSE VFonts.StringWidth[size]; v ฌ Labels.Create[ info:[parent: tool.printerStatusViewer, name: name, wx: posX, wy: posY, border: FALSE], paint: FALSE]; posX ฌ posX+v.ww+xBase; v ฌ Labels.Create[ info:[parent: tool.printerStatusViewer, wx: posX, wy: posY, ww: width, border: FALSE], paint: FALSE]; posX ฌ posX+v.ww+xBase; }; xBase: INT = 2; -- offset from left edge yBase: INT = 2; -- offset from viewer top ySpace: INT = 16; -- vertical space between labels posX, posY: INT; -- keeps track of various x,y positions v: Viewer; -- work pointer for viewers that are not kept permanently tool.printerStatusViewer ฌ Containers.Create[ info: [parent: tool.viewer, scrollable: FALSE, wx: 0, wy: 0, ww: 9999, wh: 0, border: FALSE], paint: FALSE]; posX ฌ xBase; posY ฌ yBase; tool.printerStatusMedia ฌ NewNamedLabel[name: "Paper:", w: 9999]; posX ฌ xBase; posY ฌ posY+ySpace; tool.printerStatusSpooler ฌ NewNamedLabel[name: "Spooler:", size: "Available "]; tool.printerStatusFormatter ฌ NewNamedLabel[name: "Formatter:", size: "Available "]; tool.printerStatusMarkingEngine ฌ NewNamedLabel[name: "Marking engine:", size: "NeedsKeyOperator "]; posY ฌ posY+ySpace; v ฌ Rules.Create[ info: [parent: tool.printerStatusViewer, wx: 0, wy: posY, ww: 9999, wh: 1], paint: FALSE]; PlaceChild[viewer: tool.printerStatusViewer, rank: serverStatus, minSize: posY+1, maxSize: posY+1]; [] ฌ RedisplayTool[tool]; TRUSTED {Process.Detach[FORK ServerStatusWatcher[tool, 30]]}; -- will compute initial display }; DestroyServerStatusViewer: PUBLIC ENTRY PROC [tool: Tool] ~ { ENABLE UNWIND => NULL; IF ~NoViewer[tool.printerStatusViewer] THEN ViewerOps.DestroyViewer[viewer: tool.printerStatusViewer, paint: FALSE]; [] ฌ RedisplayTool[tool]; BROADCAST tool.printerStatusTimer; -- will wake up the process and kill it since viewer destroyed }; ServerStatusWatcher: PROC [tool: Tool, delay: INT] ~ { SetServerStatusTimer: ENTRY PROC [tool: Tool, value: INT] ~ TRUSTED { ENABLE UNWIND => NULL; Process.SetTimeout[@(tool.printerStatusTimer), Process.SecondsToTicks[value]]; BROADCAST tool.printerStatusTimer; }; WaitServerStatusTimer: ENTRY PROC [tool: Tool] ~ { ENABLE UNWIND => NULL; WAIT tool.printerStatusTimer; }; Report: PROC [v: Viewer, new: ROPE] ~ { Labels.Set[v, new]; SELECT TRUE FROM Rope.Equal[new, "available", FALSE] => Labels.SetDisplayStyle[v, $BlackOnWhite]; Rope.Equal[new, "busy", FALSE] => Labels.SetDisplayStyle[v, $BlackOnGrey]; ENDCASE => Labels.SetDisplayStyle[v, $WhiteOnBlack]; }; previousStatus: XNSPrint.PrinterStatus; first: BOOL ฌ TRUE; -- First time thru previousMedia: ROPE ฌ "?"; UNTIL NoViewer[tool.printerStatusViewer] DO -- Till death do us part ... IF tool.printerStatusViewer.visible THEN { -- do the display, maybe restore sampling delay currentStatus: XNSPrint.PrinterStatus; statusSucceded: BOOL ฌ TRUE; currentMedia: ROPE ฌ NIL; SetServerStatusTimer[tool, delay]; currentStatus ฌ XNSPrint.GetPrinterStatus[tool.printerName ! XNSPrint.Error => {tool.feedBack.PutF1["Problem with printer: %g\n", IO.rope[explanation]]; statusSucceded ฌ FALSE; CONTINUE} ].answer; IF statusSucceded THEN { -- the printer responded IF first OR previousStatus.spooler#currentStatus.spooler THEN Report[tool.printerStatusSpooler, PrintingAux.ExposeSpoolerStatus[currentStatus.spooler, 0]]; IF first OR previousStatus.formatter#currentStatus.formatter THEN Report[tool.printerStatusFormatter, PrintingAux.ExposeFormatterStatus[currentStatus.formatter, 0]]; IF first OR previousStatus.printer#currentStatus.printer THEN Report[tool.printerStatusMarkingEngine, PrintingAux.ExposeMarkingEngineStatus[currentStatus.printer, 0]]; FOR mList: LIST OF ROPE ฌ currentStatus.media, mList.rest WHILE mList#NIL DO IF Rope.IsEmpty[currentMedia] THEN currentMedia ฌ mList.first ELSE currentMedia ฌ Rope.Cat[currentMedia, ",", mList.first]; ENDLOOP; IF NOT Rope.Equal[currentMedia, previousMedia] THEN Labels.Set[tool.printerStatusMedia, currentMedia]; previousStatus ฌ currentStatus; previousMedia ฌ currentMedia; first ฌ FALSE; }; } ELSE { -- don't display anything, but reduce timeout to catch visible again SetServerStatusTimer[tool, 1]; }; WaitServerStatusTimer[tool]; ENDLOOP; }; CreateStatusReport: PUBLIC ENTRY PROC [tool: Tool, title: ROPE] RETURNS [state: StatusReport] ~ { ENABLE UNWIND => NULL; x: INT ฌ 2; -- current position to insert a new viewer inside status viewer yOffset: INT = 2; -- offset from viewer top state ฌ NEW [StatusReportRep ฌ [tool: tool]]; IF tool.requestStatusContainer=NIL OR tool.requestStatusContainer.destroyed THEN { -- Create the container that includes all status reports tool.requestStatusContainer ฌ Containers.Create[ info: [parent: tool.viewer, scrollable: TRUE, ww: 9999, wh: 0, border: FALSE], paint: FALSE]; tool.requestStatusRule ฌ Rules.Create[info: [parent: tool.viewer, ww: 9999, wh: 1], paint: FALSE]; }; state.viewer ฌ Containers.Create[ info: [parent: tool.requestStatusContainer, scrollable: FALSE, wx: 0, wy: 0, ww: 9999, wh: 24, border: TRUE], paint: FALSE]; state.info ฌ Labels.Create[ info:[parent: state.viewer, wx: x, wy: yOffset, ww: 0, wh: 16, scrollable: FALSE, border: FALSE], paint: FALSE]; -- pie/stop and server status are not used simultaneously state.pie ฌ PieViewers.Create[parent: state.viewer, x: x, y: yOffset, diameter: 16, total: 100.0]; PieViewers.Set[state.pie, 100.0]; x ฌ x + state.pie.ww + 4; state.stop ฌ Buttons.Create[ info: [parent: state.viewer, name: "STOP", wx: x, wy: yOffset, scrollable: FALSE, border: TRUE], proc: StopButtonProc, clientData: state, fork: FALSE, guarded: TRUE, paint: FALSE]; state.comment ฌ Labels.Create[ info:[parent: state.viewer, name: title, wx: 70, wy: yOffset, scrollable: FALSE, border: FALSE], paint: FALSE]; }; ResizeStatusContainer: PUBLIC PROC [tool: Tool] ~ { yOffset: INT = 2; -- separate status reports by that amount Resize: PROC [] ~ { -- protected by a viewer lock curY: INT ฌ 0; FOR v: Viewer ฌ tool.requestStatusContainer.child, v.sibling UNTIL v=NIL DO IF v.destroyed THEN LOOP; curY ฌ curY+yOffset; ViewerOps.EstablishViewerPosition[viewer: v, x: v.wx, y: curY, w: v.ww, h: v.wh]; curY ฌ curY+v.wh; ENDLOOP; IF curY#0 THEN { -- the container is not empty PlaceChild[viewer: tool.requestStatusContainer, rank: statusContainer, minSize: 0, maxSize: curY]; PlaceChild[viewer: tool.requestStatusRule, rank: statusRule, minSize: 1, maxSize: 1]; } ELSE { ViewerOps.DestroyViewer[viewer: tool.requestStatusContainer, paint: FALSE]; tool.requestStatusContainer ฌ NIL; ViewerOps.DestroyViewer[viewer: tool.requestStatusRule, paint: FALSE]; tool.requestStatusRule ฌ NIL; }; IF NOT RedisplayTool[tool] THEN ViewerOps.PaintViewer[tool.requestStatusContainer, client]; }; IF tool.viewer=NIL OR tool.viewer.destroyed THEN RETURN; -- don't bother... ViewerLocks.CallUnderWriteLock[Resize, tool.viewer]; }; StopButtonProc: Buttons.ButtonProc ~ { state: StatusReport = NARROW [clientData]; state.stopRequired ฌ TRUE; Buttons.SetDisplayStyle[state.stop, $BlackOnGrey]; }; SetSendingStatus: PUBLIC PROC [state: StatusReport] ~ { w: INT = state.comment.wx-state.info.wx-4; -- Hum Hum ... ViewerOps.DestroyViewer[state.pie]; state.pie ฌ NIL; ViewerOps.DestroyViewer[state.stop]; state.stop ฌ NIL; ViewerOps.MoveViewer[viewer: state.info, x: state.info.wx, y: state.info.wy, w: w, h: state.info.wh]; Labels.Set[label: state.info, value: "Sending"]; }; PrintStatusUpdate: PUBLIC XNSPrint.StatusChangedProc ~ { state: StatusReport ฌ NARROW [clientData]; notExplicit: BOOL ฌ Rope.IsEmpty[request.lastStatus.statusMessage]; -- no explicit message msg: ROPE ฌ PrintingAux.ExposeInterpressMasterStatus[request.lastStatus.status, 0]; IF state.viewer=NIL OR state.viewer.destroyed THEN RETURN; IF ~notExplicit THEN IO.PutF[state.tool.feedBack, "Status of %g: %g -> %g\n", IO.rope[request.context.printObjectName], IO.rope[msg], IO.rope[request.lastStatus.statusMessage]]; SELECT request.lastStatus.status FROM pending, inProgress, held => Labels.Set[label: state.info, value: msg]; completed, completedWithWarning, rejected, aborted, canceled, unknown => { -- Destroy status report and indicate in log IF notExplicit THEN IO.PutF[state.tool.feedBack, "%g: %g\n", IO.rope[request.context.printObjectName], IO.rope[msg]]; XNSPrint.UnRegisterPrintRequest[request]; ViewerOps.DestroyViewer[viewer: state.viewer, paint: FALSE]; ResizeStatusContainer[state.tool]; request.context ฌ NIL; -- Avoid circularities state.tool ฌ NIL; }; ENDCASE => ERROR; -- not supported status value, call maintenance... }; XTSetterPositionInfo: TYPE ~ REF XTSetterPositionInfoRep; XTSetterPositionInfoRep: TYPE ~ RECORD [ minSize: INT, -- minimum size for viewer maxSize: INT, -- maximum useful size for viewer, <0 if infinitely extensible rank: INT -- the display order in the window ]; PlaceChild: PROC [viewer: Viewer, rank: ViewerRanking, minSize, maxSize: INT] ~ { ViewerOps.AddProp[viewer, $XTSViewerPositionInfo, NEW[XTSetterPositionInfoRep ฌ [minSize: minSize, maxSize: maxSize, rank: rank.ORD]]]; }; XTSViewerAdjust: ViewerClasses.AdjustProc ~ { Element: TYPE ~ REF ElementRep; ElementRep: TYPE ~ RECORD [ v: Viewer ฌ NIL, -- this position element is for this viewer rank: INT ฌ -1, -- at which viewer should be displayed, should be >=0 height: INT ฌ 0, -- computed delta: INT ฌ 0, -- extensible by that much more, <0 means infinitely next: Element ฌ NIL -- chain to next in list ]; head: Element ฌ NEW [ElementRep]; -- dummy head element, rank = -1 free: INT ฌ self.ch; -- how much free space is available in the client space sumDelta: INT ฌ 0; -- how much the limited extension could be infinite: INT ฌ 0; -- number of viewers with infinite stretch curY: INT ฌ 0; -- current y position when relocating children step: INT = 2; -- Free space between sub-viewers FOR v: Viewer ฌ self.child, v.sibling UNTIL v=NIL DO -- Sort by rank IF v.destroyed THEN adjusted ฌ TRUE ELSE WITH ViewerOps.FetchProp[v, $XTSViewerPositionInfo] SELECT FROM positionInfo: XTSetterPositionInfo => { current: Element ฌ NEW [ElementRep ฌ [ v: v, rank: positionInfo.rank, delta: positionInfo.maxSize - positionInfo.minSize, height: positionInfo.minSize ]]; free ฌ free - (current.height + step); IF current.delta>0 THEN sumDelta ฌ sumDelta+current.delta; IF current.delta<0 THEN infinite ฌ infinite+1; FOR e: Element ฌ head, e.next WHILE e#NIL DO -- Insert in list according to rank IF e.next=NIL OR e.next.rank>current.rank THEN { current.next ฌ e.next; e.next ฌ current; EXIT; }; ENDLOOP; }; ENDCASE => NULL; -- All children must have the position property... ENDLOOP; IF free>0 THEN { -- there is still some free space to allocate total: INT = MIN [free, sumDelta]; -- total stretch to allocate for finite-stretch viewers FOR e: Element ฌ head.next, e.next WHILE e#NIL DO -- allocate to finite-stretch viewers add: INT = IF e.delta>0 THEN (total*e.delta)/sumDelta ELSE 0; e.height ฌ e.height+add; free ฌ free-add; ENDLOOP; IF free>0 AND infinite#0 THEN { -- allocate remainder to infinite-stretch viewers add: INT = free/infinite; FOR e: Element ฌ head.next, e.next WHILE e#NIL DO IF e.delta<0 THEN e.height ฌ e.height+add; ENDLOOP; }; }; FOR e: Element ฌ head.next, e.next WHILE e#NIL DO -- relocate all subviewers ww: INT = MAX [5, self.cw - e.v.wx]; IF e.v.wy#curY OR e.v.wh#e.height OR e.v.ww#ww THEN { adjusted ฌ TRUE; ViewerOps.EstablishViewerPosition[viewer: e.v, x: e.v.wx, y: curY, w: ww, h: e.height]; }; curY ฌ curY+e.height +step; ENDLOOP; }; RedisplayTool: PROC [tool: Tool] RETURNS [painted: BOOL ฌ FALSE] ~ { DoIt: PROC [] ~ { -- Under viewer lock painted ฌ XTSViewerAdjust[tool.viewer]; IF painted THEN ViewerOps.PaintViewer[tool.viewer, client]; }; IF tool.viewer=NIL OR tool.viewer.destroyed THEN RETURN[painted: TRUE]; -- don't bother... ViewerLocks.CallUnderWriteLock[DoIt, tool.viewer]; }; NoViewer: PROC [v: Viewer] RETURNS [BOOL] ~ INLINE { RETURN [v=NIL OR v.destroyed] }; SetupPrinterVersion: PROC [tool: Tool] ~ { pVers: PrinterVersion ฌ NARROW [SymTab.Fetch[printerVersions, tool.printerName].val]; IF pVers=NIL THEN pVers ฌ NARROW [SymTab.Fetch[ropeToVersion, " DEFAULT "].val]; IF pVers=NIL THEN ERROR; -- call support... tool.version ฌ pVers; }; DefinePrinterVersions: PROC [versions: LIST OF ROPE] ~ { IF printerVersions=NIL THEN printerVersions ฌ SymTab.Create[case: FALSE]; FOR l: LIST OF ROPE ฌ versions, l.rest.rest UNTIL l=NIL OR l.rest=NIL DO name: ROPE = l.first; attribute: ROPE = l.rest.first; version: PrinterVersion ฌ NARROW [SymTab.Fetch[ropeToVersion, l.rest.first].val]; IF version=NIL THEN version ฌ NARROW [SymTab.Fetch[ropeToVersion, " DEFAULT "].val]; [] ฌ SymTab.Store[printerVersions, name, version]; ENDLOOP; }; cmdDoc: ROPE = "[]\nCreate a viewer to print things on an XNS based printer.\nArguments:\n Print on that service"; cmdUsage: ROPE = Rope.Concat["Usage: XTSetter ", cmdDoc]; XTSetterCommand: Commander.CommandProc ~ { printer: Args.Arg; [printer] ฌ Args.ArgsGet[cmd, "[s" ! Args.Error => {msg ฌ reason; CONTINUE}]; IF msg # NIL THEN RETURN[$Failure, cmdUsage]; IF Rope.IsEmpty[printer.rope] THEN printer.rope ฌ XNSPrint.GetDefaults[].printerName; [] ฌ NewTool[printer.rope, cmd.err ! Error => GOTO failed]; EXITS failed => RETURN [$Failure]; }; NewProfile: UserProfile.ProfileChangedProc ~ { DefaultOptionsFromProfile[]; }; NewUser: XNSCredentials.XNSCredentialsChangeProc ~ { DefaultOptionsFromProfile[]; }; Init: PROC [] ~ { Define: PROC [type: ROPE, version: IPMaster.Version, mayCompress: BOOL, shouldCompress: BOOL, hasPressFonts: BOOL] ~ { [] ฌ SymTab.Store[ropeToVersion, type, NEW [PrinterVersionRep ฌ [version, mayCompress, mayCompress AND shouldCompress, hasPressFonts]]]; }; xTSViewerIcon ฌ Icons.NewIconFromFile["XTSetter.icons", 0]; xTSViewerClass ฌ NEW[ViewerClasses.ViewerClassRec ฌ[ adjust: XTSViewerAdjust, icon: xTSViewerIcon, topDownCoordSys: TRUE]]; ViewerOps.RegisterViewerClass[$XTSetter, xTSViewerClass]; ropeToVersion ฌ SymTab.Create[case: FALSE]; Define[" DEFAULT ", [3, 0], TRUE, FALSE, TRUE]; -- default for undeclared rope versions Define["3.0-PGS", [3, 0], TRUE, FALSE, TRUE]; -- Quoth Define["3.0-CS", [3, 0], TRUE, TRUE, FALSE]; -- Zipper Define["2.1-RLS", [2, 1], FALSE, FALSE, FALSE]; -- Perfector Define["1.0", [1, 0], FALSE, FALSE, FALSE]; -- Scripto DefinePrinterVersions[standardVersions]; UserProfile.CallWhenProfileChanges[NewProfile]; XNSCredentials.RegisterForChange[NewUser]; Commander.Register[key: "XTSetter", proc: XTSetterCommand, doc: cmdDoc]; }; Init[]; END. h XTSetterImpl.mesa Copyright ำ 1987, 1992 by Xerox Corporation. All rights reserved. Jean-Marc Frailong, November 22, 1988 9:21:33 am PST Bloomenthal, November 25, 1987 3:26:42 pm PST Viewer tool for XNS printing Weiser, January 22, 1991 0:11 am PST Kenneth A. Pier, April 1, 1991 3:31 pm PST Chauser, April 15, 1991 11:13 am PDT Willie-s, April 6, 1992 1:01 pm PDT Global static variables Tool initialization and access Return a tool for the required printer, force subviewers if required. A tool may be found among existing viewers. printer default to profile entry. Create a new tool for the specified server. feedBack is used to log errors. The viewer is structured as follows: - a menu line - an options viewer (Not initially created, added later on by clicking the options cmd) - a status container containing one status viewer per pending operation (Created when needed) - a typescript for user feedback and error messages Create a viewer for the tool based on the current info data structure The viewer is structured as follows: - a menu line - an options viewer (Not initially created, added later on by clicking the options cmd) - a status container containing one status viewer per pending operation (Created when needed) - a typescript for user feedback and error messages Add a new button in the menu line(s). Create the basic viewer Create the menu Create the typescript area Display the viewer properly Menu buttons Create a new occurence of the tool with the currently selected rope as printer name Print the left half of the B&W screen Print the B&W screen Print the right half of the B&W screen Print the color screen Print the currently selected object, whatever it may be: - if something looking like a filename is currently selected, print this file after applying FileDWIM hints - if a Tioga/Typescript viewer is currently selected, print its contents - else, try something intelligent (no guarantee whatsoever) Returns TRUE if this looks like a valid file name Apply hint to find a contextFileName from the viewer, then apply FileDWIM.ResolveHint to derive a full file name. All FS errors result in hint being sent back as the result. commandToolName: ROPE = "CommandTool: WD = "; Toggle visibility of options panel Toggle visibility of server status panel Options menu management Types, constants and utilities Boolean buttons Boolean buttons control directly a boolean variable. Create a button that controls a boolean variable and is initially located at pos in parent Init is the initial value. If possible is false, the true state is displayed as BlackOnGrey instead of the expected WhiteOnBlack Toggle a boolean-valued button Return the current value of a boolean button Set the current value of a boolean button Integer buttons Integer buttons control an integer value that may be absent (defaulted by the client when getting them) Create a button with integer values. Initial state is empty if defined is FALSE, else it gets the init value. Return the current state of an integer-valued button Set the value of an integer-valued button Click an integer-valued button: make it pending delete Real buttons Real buttons control a real value that may be absent (defaulted by the client when getting them) Create a button with real values. Initial state is empty if defined is FALSE, else it gets the init value. Return the current state of a real-valued button Set the value of a real-valued button Click a real-valued button: make it pending delete Rope buttons Rope buttons control a rope with a set of standard default values Create a button with rope values Return the current state of a rope-valued button Set the value of a rope-valued button Click a rope-valued button: progress in list or make it pending-delete Options handling Create a new subviewer for options management. All initial values taken from current tool options. First line of panel: Compress, keepIP, scale and style selection Second line of panel: Flags, numbers Third line of panel: Paper selection Third line of panel: Paper selection Terminating rule of options panel and adjust the viewer height correctly Repaint everything Returns current options from tool. Returns current options from tool. Returns current options from tool. Sets all the tool options Need to do something about telephone here Returns a reasonable set of default options Initialize profile-derived entries in defaultOptions. Entries derived from context are not setup here because the order of Profile call-backs is not specified! backward compatibility for XTSetter.UsePressFonts user profile option options.compress _ default from type; options.copyCount _ default from type; options.pageFirst _ default from type; options.pageLast _ default from type; options.tiogaScale _ default from type; Print server status viewer management Create the server status viewer and insert it in the tool. Insert 2 labels at posX, posY, 1st carries name, second will carry variable info. Size of 2nd label is set by the display size of size, or w if NIL. First line of the printer status viewer: Media availability Second line of the printer status viewer Add the terminating rule Setup sizing and position information Repaint tool and start the update process Destroy the printer status viewer. This runs as a separate process that maintains the server status window Repaints the window each time the timer is exhausted/modified. To reduce load on XNS, no queries are made while the viewer is not visible. On the reverse, a redisplay will be forced shortly after the viewer is visible again. Process ends when the window has been destroyed, either directly by the status button or because the master viewer itself has been destroyed. Updates the time-out between server status viewer updates and forces the viewer to be updated immediately. Wait until the timer is exhausted or forced Update one of the 3 status reports Print request status viewers management Create a status report handle and the associated viewer. Recomputes screen positions for comfort. Create the status viewer itself Reposition all the status elements in the container passed It's assumed that the viewer is not properly painted at this moment ViewerOps.MoveViewer[viewer: v, x: v.wx, y: curY, w: v.ww, h: v.wh, paint: FALSE]; Just set the stop flag in the state, clients will look it up Kill pie & stop viewers, readjust info width, set it to Sending. Modify the current print status reported by the print server Viewer class The XTSetter viewer class offers dynamic repositioning and sizing of subviewers. All subviewers must have a property set inidcating their display rank, minimum size, maximum useful size. Inifinitely stretchable children may also be used. Various utilities Returns TRUE if the viewer does not exist (i.e. is NIL) or has been destroyed. Setup the printer version field of the tool. CommandTool interface PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] The command tool interface to create a new XTSetter Initialization ส%•NewlineDelimiter –(cedarcode) style™codešœ™Kšœ ฯeœ6™BK™4K™-K™Kšœ™K™$K™*K™$K™#K™—šฯk ˜ Kšœžœ˜!Kšœžœ/˜˜QKšœ žœ2˜@Kšœ žœ˜'Kšœ žœช˜นKšœ žœx˜‰Kšœžœ˜&Kšœžœ˜%Kšœžœ/˜CKšœ žœช˜ธKšœ˜—K˜š ัbln œžœžœžœžœ ˜7K˜—KšžœPžœžœศ˜ตKšžœ˜!K˜šœž˜K˜šžœฯn œ˜3K˜—šœ žœžœ˜/K˜—KšœžœD˜W—head™Kšœ!ฯc˜1šœ+ก˜CK˜—šœกT˜mK˜—Kšœ žœžœžœก-˜Fšœ žœžœžœก.˜HK˜—Kšœก˜7Kšœก˜5š œžœžœžœžœก˜FKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜——™code2š  œžœžœžœžœ˜'K˜—š œžœžœ žœžœžœžœžœžœ˜\Kšœ“™“š  œ˜"šžœžœ žœž˜MKšžœžœ˜—Kšœžœ ˜Kšžœžœ˜K˜—Kšžœžœฯtœ˜KKšžœžœ)ก˜PKš žœžœžœ!ขœขœ˜OK˜K˜—š  œžœ žœ žœžœ˜HJ™K™$K™ K™WK™]K™3—šžœ˜Kšœ7žœžœ˜_Kšžœ˜Kšžœ˜K˜—Kšœžœ$˜.K˜PKšœ˜K˜'K˜;Kšœก1˜EKšœ9žœ˜TK˜K™—š  œžœ˜#K™E™$K™ K™WK™]K™3—š  œž œžœžœžœžœžœžœ˜zK™%Kšœžœ˜•Kšœ,˜,K˜—Kšœ&˜&Kšœ˜™˜7KšœQžœ˜dKšœžœก)˜6K˜——™Kšœ1žœ˜7Kšœ2˜2Kšœ1˜1Kšœ3˜3Kšœ5˜5Kšœ5žœ˜;Kšœ9žœ˜?KšœCžœ˜IKšœ%˜%—™˜KšœCžœ˜JKšœžœ˜—Kšœ)˜)KšœK˜KKšœ3žœ˜P—™Kšœ(˜(—K˜K˜—š œžœžœ žœ˜5K˜Kšžœ'˜-K˜K˜—š  œžœžœžœ˜/Kšžœžœžœ˜Kšœ%˜%K˜——™ š  œ˜K™SKšœ žœ ˜ Kšœ žœ&˜3Kšžœžœ0žœ˜XK˜K˜—š œ˜$K™%Kšœ žœ ˜ Kšœ!˜!K˜K˜—š  œ˜ K™Kšœ žœ ˜ Kšœ˜K˜K˜—š œ˜%K™&Kšœ žœ ˜ Kšœ"˜"K˜K˜—š œ˜%K™Kšœ žœ ˜ Kšžœžœ"˜FKšžœF˜JK˜K˜—š  œ˜™8K™kK™HK™;—š  œžœžœžœžœ˜6Kšœžœ%™1Kšœžœ˜Kš žœ žœžœžœก˜7Kš žœ,žœžœžœก˜XKšžœžœก ˜K˜—š   œžœžœ žœ žœ˜DKšœvžœ6™ฎKšžœžœ žœžœ˜!Kšœžœ˜ Kšœžœ™-Kš žœžœžœžœก ˜1K˜š žœžœžœžœก˜IK˜—K˜—šœ žœก˜$Kšœ&˜&K˜—šžœก˜(KšžœA˜CK˜——Kšžœ žœ˜K˜K˜—š  œ˜!K™"Kšœ žœ ˜ Kšžœžœžœžœ˜XKšžœ˜ K˜K˜—š œ˜&K™(Kšœ žœ ˜ Kšžœžœžœ$žœ˜iKšžœ!˜%K˜——™™šœžœžœžœ˜K˜—Kšœ žœ˜Kšœ žœ˜šœ žœ˜K˜——™™4K™—š œžœžœ,žœ žœžœžœ˜กK™ZK™Kš œžœžœžœžœ žœžœ˜d˜KšœAžœ˜GKšœ˜Kšœžœ˜ Kšœžœ˜ Kšœ˜K˜—K˜-Kšœžœ ˜(K˜K˜—š œ˜'K™Kšœžœ˜(Kšœžœ ˜%Kšžœ žœžœ˜+K˜K˜—š  œžœžœžœ˜:K™,Kšžœ˜K˜K˜—š  œžœžœ˜7K™)K˜Kšœ&žœžœžœ˜XK˜K˜——™™gK™—š œžœžœžœžœ žœžœžœžœžœ˜จKšœJžœ™mKšœžœ%˜0˜KšœAžœ˜HKšœ˜Kšœžœ˜ Kšœ˜Kšœž˜ K˜—Kšœ1ก"˜S˜+KšœQžœ˜XKšœžœ˜—K˜K˜#K˜K˜—š  œžœžœžœ˜šžœžœก)˜Qšžœžœžœ˜"KšœD˜DKšœ$˜$K˜—Kšœ@˜@KšœA˜AKšœD˜DKšœA˜AKšœD˜DKšœB˜BKšœ žœ˜ชKšฯb)™)KšœA˜AKšœB˜BKšœ>˜>Kšœ˜—K˜K˜—š œžœžœžœ˜=K™+K˜3Kšœ žœ!ก"˜PK˜(K˜"K˜$K˜&K˜K˜—š œžœ˜&KšœŸ™Ÿš œ˜ K˜ Kš žœžœ žœžœžœ˜˜5Kš žœ/žœžœ žœžœ˜O—Kšœ'™'K˜Kšœ;žœ…˜ฤKšœ=žœ˜_Kšœ(˜(KšœKžœ˜QKšœ&ก2˜XK˜K˜———™%š œžœžœžœ˜˜aK˜K˜—š œžœžœ˜6K™GJšœQžœŒ™เJ™š  œžœžœžœžœ˜EK™jKšžœžœžœ˜KšœN˜NKšž œ˜"K˜—š œžœžœ˜2K™+Kšžœžœžœ˜Kšžœ˜K˜—š œžœžœ˜'K™"Kšœ˜šžœžœž˜Kšœžœ.˜PKšœžœ-˜JKšžœ-˜4—K˜—Kšœ'˜'Kšœžœžœก˜&Kšœžœ˜šžœ$žœก˜Hšžœ"žœก/˜ZKšœ&˜&Kšœžœžœ˜Kšœžœžœ˜Kšœ"˜"˜˜LKšœžœก"˜,Kšœ˜K˜—š  œžœ9žœ˜QKšœ2žœKžœ˜‡K˜K˜—š œ˜-Kšœ žœžœ ˜šœ žœžœ˜Kšœ žœก+˜Kšœžœžœก7˜Zš žœ žœžœžœก%˜WKš œžœžœ žœžœ˜=K˜K˜Kšžœ˜—šžœžœ žœก1˜QKšœžœ˜šžœ žœžœž˜1Kšžœ žœ˜*Kšžœ˜—Kšœ˜—Kšœ˜—š žœ žœžœžœก˜LKšœžœžœ˜$šžœ žœžœ žœ˜5Kšœ žœ˜KšœW˜WKšœ˜—K˜Kšžœ˜—K˜K˜—š   œžœžœ žœžœ˜Dš œžœก˜&K˜'Kšžœ žœ,˜;K˜—Kš žœ žœžœžœžœ žœก˜ZKšœ2˜2K˜——™š  œžœ žœžœžœ˜4Kšœžœ'žœ™NKšžœžœžœ ˜K˜K˜—š œžœ˜*K™,Kšœžœ7˜UKšžœžœžœ žœ0˜PKš žœžœžœžœก˜+K˜K˜K˜—š  œžœ žœžœžœ˜8Kšžœžœžœ'žœ˜Išžœžœžœžœžœžœžœžœž˜HKšœžœžœ˜5Kšœžœ1˜Qšžœ žœž˜Kšœ žœ0˜@—K˜2Kšžœ˜—K˜——™šœžœ˜K˜—Kšœ žœ+˜9K˜š œ˜*Kš žœžœ žœžœžœžœ™?K™3Kšœ˜KšœBžœ˜MKšžœžœžœžœ˜-Kšžœžœขœ˜UKšœ.žœ ˜;šž˜Kšœ žœ ˜—K˜K˜——™š  œ$˜.Kšœ˜Kšœ˜K˜—š œ-˜4Kšœ˜Kšœ˜K˜—–x[key: ROPE, proc: Commander.CommandProc, doc: ROPE _ NIL, clientData: REF ANY _ NIL, interpreted: BOOL _ TRUE]š œžœ˜š  œžœžœ*žœžœžœ˜vKšœ'žœ9žœ"˜ˆK˜—K˜;šœžœ ˜4Kšœ˜K˜Kšœžœ˜—Kšœ9˜9Kšœ$žœ˜+Kšœžœž œก'˜WKšœžœž œก˜6Kšœžœก ˜6Kšœžœก ˜