Most information in the Tornado browser is presented in the form of windows. For an introduction to the browser, see the Tornado User's Guide: Browser. The following sections step through the process of creating display windows in the browser and using them to display the data extracted in 5.3 Extracting Information from a Structure.
In the UNIX browser, most information is presented in hierarchy windows. These are windows that display information in a hierarchical or list format. The windows are defined using UI Tcl; for more information, see the on-line help.
Use the core routines described in 5.3 Extracting Information from a Structure to produce the browser panel shown in Figure 5-3. The steps in creating the new window display are:
Hierarchy windows are created with the Tcl procedure hierarchyCreate. The -destroy option calls the routine ifDestroyed if the user dismisses the new window from the window manager (see Installing the New Browser Panel). The -change option causes any values that have been updated between one evaluation and the next to be highlighted. (In Figure 5-3 this occurred with packets received, packets sent, and errors.) The new window is called Network Interfaces. The complete command to create the window is:
hierarchyCreate -destroy ifDestroyed -change "Network Interfaces"
The next step is to use hierarchySetStructure to describe the structure of the hierarchy that the window will display. For a detailed explanation of this and other procedures, see the on-line help.
The format of data for a hierarchy window mirrors that of the structure string. Arrays of objects are surrounded by braces. Simple objects follow one another separated by spaces; nested objects are placed in braces. The output of the procedure is a nested list in the standard Tcl format.
The first six elements of the display (name through mtu) are simple objects, represented in the structure description by their names:
name flags addr destaddr metric mtu
Each nested element consists of a bracketed list which itself has two elements, the first being the name of the header item (the folder) and the second the sublist of subordinate items:
{packets {received sent}} {errors {input output collisions}}
To arrange for an array of structures (in this example, a listing of data for all network interfaces), create a list whose first element is the special name + and whose second element is the substructure, enclosed in braces. This bracketed list becomes the second argument for the hierarchySetStructure procedure; the first argument is the window name.
hierarchySetStructure "Network Interfaces" \ {+ {name flags addr destaddr metric mtu \ {packets {received sent}} \ {errors {input output collisions}}}}
This code must be in the browser initialization file so that the browser creates this hierarchy when it starts (host/resource/tcl/app-config/Browser/01NetBrws.tcl).
The next step is to create a procedure that arranges the data from the network information-gathering routines (described in 5.3 Extracting Information from a Structure) into a form suitable for the hierarchySetValues procedure. The format of data for a hierarchy mirrors that of the structure string. For the window shown in Figure 5-3, the value string used to fill the data slots is:
{{ul0 {(0xf1) UP POINT-TO-POINT RUNNING } 127.0.1.7 147.11.80.6 \ 0 1536 {459 922} {0 0 0}} \ {lo0 {(0x69) UP LOOPBACK RUNNING ARP } 127.0.0.1 0.0.0.0 \ 0 4096 {3 3} {0 0 0}}}
Create a procedure that generates such a list (including formatting braces) from the data returned by the gathering routines. The Tcl lappend procedure serves this purpose by automatically adding braces when necessary (as when the new list element contains embedded spaces). First consider the data for just one interface, whose address is presumed to be in the variable netIf. Initialize a variable, thisIf, to the empty string, and then append the items called for one by one.
set thisIf "" set ifInfo [netIfInfo $netIf] lappend thisIf [format "%s%d" [lindex $ifInfo 0] \ [lindex $ifInfo 1]] lappend thisIf [format "(%#x) %s" \ [lindex $ifInfo 2] [ifFlagsFormat [lindex $ifInfo 2]]] set ifAddrList [netIfAddrList $netIf] lappend thisIf [ifAddrFormat [lrange $ifAddrList 0 3]] lappend thisIf [ifAddrFormat [lrange $ifAddrList 4 7]] # metric lappend thisIf [lindex $ifInfo 4] # mtu lappend thisIf [expr [lindex $ifInfo 3]] # add packet arrays lappend thisIf [list [expr [lindex $ifInfo 5]] \ [expr [lindex $ifInfo 7]]] # add error/collision counts lappend thisIf [list [expr [lindex $ifInfo 6]] \ [expr [lindex $ifInfo 8]] \ [expr [lindex $ifInfo 9]]]
To complete the data collection for the window, you need only wrap this code in a loop which queries all network interfaces and accumulates the list generated by the above code into a "list of lists." Note how the nesting of the lappend procedure simplifies the creation of nested lists.
proc getAllIf {} { set allIf "" foreach netIf [netIfList] { # code fragment above lappend allIf $thisIf } return $allIf }
This makes it possible to generate the data by calling hierarchySetValues. The output will be in a form ready to be displayed as in Figure 5-3:
hierarchySetValues "Network Interfaces" [getAllIf]
Two steps are required to add this panel to the browser. First, create a toolbar button to request the display of the panel. Second, insert the panel value-computation routine into the browser main loop so that the information is updated regularly.
Add a toolbar button containing the string "netif" to the browser toolbar1 , with the following command:
toolBarItemCreate netif button {ifPost}
The Tcl procedure ifPost uses a global variable to keep track of whether the network interface browser is posted or not.
set netIfPosted 0 proc ifPost {} { global netIfPosted hierarchyPost "Network Interfaces" set netIfPosted 1 ifBrowse }
When you created the hierarchy window (in Defining a New Window), you indicated you wanted to call the procedure ifDestroyed when the window manager dismisses the interface browser. The purpose of ifDestroyed is to update the state variable.
proc ifDestroyed {name} { global netIfPosted set netIfPosted 0 }
You want to update the network interface panel each time the browser updates other windows, either because the user presses the immediate update button or because the browser is in continuous update mode and the update interval elapses. To do this, call browserAuxProcAdd with the name of a procedure to invoke each time the browser is in its update cycle:
browserAuxProcAdd ifBrowse
This procedure, ifBrowse, checks the status of the global variable to see if the panel has been posted. If so, it collects the data and installs it in the hierarchy window. This completes the process of collecting data and displaying it in the browser.
proc ifBrowse {} { global netIfPosted if {! $netIfPosted} return hierarchySetValues "Network Interfaces" $allIf }
The browser procedures are combined in a file in installDir/host/resource/tcl/app-config/Browser/01NetBrws.tcl, which also sources the data extraction routines developed earlier.
# source the data extraction and formatting routines source [wtxPath host resource tcl]net-core.tcl
The following sample Tcl application extends the Tornado browser by adding a new page to display network interface information. Add extension files following these guidelines:
source [wtxPath host resource tcl]net-core.tcl
lappend pageList "Network Information"
proc invokeNetworkInformation {} { global currentBrowserProc global autoResize allControlsDestroy Browser setupNetworkInfoPage set currentBrowserProc refreshNetworkInfoPage if {$autoResize} { windowSizeCallbackSet Browser "adjustNetworkInfoPage" } }
invokeDescriptionStringW/oSpaces
proc setupNetworkInfoPage {} { global autoResize
proc adjustNetworkInfoPage {} { global autoResize if [controlExists Browser.networkInfo] { set clientSz [windowClientSizeGet Browser] if {$autoResize} { set maxXExtent [expr [lindex $clientSz 0] - 14] set maxYExtent [expr [lindex $clientSz 1] - 14] } { set maxXExtent 300 set maxYExtent 160 } controlPositionSet Browser.networkInfo 7 25 controlSizeSet Browser.networkInfo $maxXExtent \ [expr $maxYExtent - 18] } }
proc refreshNetworkInfoPage {} { controlValuesSet Browser.networkInfo [getAllIf] }
Example 5-4 gives the complete code to install the sample Tcl application (developed in Generating the Data) in the browser on a Windows host.
########################################################################## # 01NetBrws.win32.tcl - sample UITcl code illustrating user extension of the # Tornado Browser. # # Copyright 1994-1997 Wind River Systems, Inc. # # This sample Tcl application extends the Tornado browser by adding a new # page to display network interface information. # ######################################################################### # Do not source this file if the platform is not win32 if {![string match *win32* [wtxHostType]]} return # source the host-independent data extraction and formatting routines source [wtxPath host resource tcl]net-core.tcl # hook our page into the browser lappend pageList "Network Information" # hook for Target Server Information panel called by Browser proc invokeNetworkInformation {} { global currentBrowserProc global autoResize allControlsDestroy Browser setupNetworkInfoPage # hook-in refresh button set currentBrowserProc refreshNetworkInfoPage # ensure window size reflects Browser's if {$autoResize} { windowSizeCallbackSet Browser "adjustNetworkInfoPage" } }
1: To have an icon appear in the toolbar button instead of the name, place an X bitmap file with the same name as the button in the directory installDir/resource/bitmaps/Browser/controls. You can do this with any Tornado tool that has a toolbar.