3.7   Tcl: Customizing the Launcher


*

NOTE: If you are not familiar with Tcl, you may want to postpone reading this section (and other sections in this book beginning with "Tcl:") until you have a chance to read B. Tcl (and perhaps some of the Tcl references recommended there).

An important reference for these examples, even if you are familiar with Tcl, is the GUI Tcl Library reference available online from Help>Manuals contents>Tornado API Reference. It describes the building blocks for the user interface (GUI) shared by the Tornado tools.

All Tornado tools can be altered to your needs (and to your taste) by adding your own Tcl code. This section has a few examples of launcher customization.

When you consider modifications to the launcher, you may want to read related code in the standard form of the launcher. The Tcl code implementing the launcher is organized as follows (all file names below are relative to WIND_BASE):

host/resource/tcl/Launch.tcl
The main launcher implementation file.

host/resource/tcl/app-config/Launch/01*.tcl
Supporting procedures and definitions (grouped into separate files by related functionality) for the launcher.

host/resource/tcl/app-config/all/host.tcl
Defaults for global settings; may be redefined for specific host types.

host/resource/tcl/app-config/all/${WIND_HOST_TYPE}.tcl
Host-specific overrides for global settings.

3.7.1   Tcl: Launcher Initialization File

When the launcher starts up, it looks for a file called .wind/launch.tcl in your home directory. If that file is present, its contents are read with the Tcl source command before the launcher puts up its initial display. Use this file to collect your custom modifications, or to incorporate shared customizations from a central repository of Tcl extensions at your site.

3.7.2   Tcl: Launcher Customization Examples

When you begin experimenting with any new system (or language), errors are to be expected. Any error messages from your launcher Tcl initialization code are captured by the launcher, and a summary of the error is displayed in a window similar to Figure 3-5.

To see the full Tcl error display, click on the Details button in the error display; click Continue to dismiss the display.

The examples in this section use the Tcl extensions summarized in Table 3-2. For detailed descriptions of these and other Tornado graphical building blocks in Tcl, see Help>Manuals contents>Tornado API Reference>GUI Tcl Library.

Table 3-2:  Tornado UI Tcl Extensions Used in Launcher Customization Examples


Tcl Extension
 
Description
 

noticePost
 
Display a popup notice or a file selector.
 
menuButtonCreate
 
Add a command to an existing menu.
 

Re-Reading Tcl Initialization

Because the launcher has no direct command-line access to Tcl, it is not as convenient as other tools (such as WindSh or CrossWind) for experimentation with Tcl extensions. The following example makes things a little easier: it adds a command to the File menu that reloads the .wind/launch.tcl file. This avoids having to Quit the launcher and invoke it again, every time you change launcher customization.

Example 3-1:  Tcl Reinitialization

# "Reinitialize" command for Launcher. 
# Adds item to File menu; calls Tcl "source" primitive directly. 
 
menuButtonCreate File "Re-Read Tcl" T { 
    source ~/.wind/launch.tcl 
}

Quit Launcher Without Prompting

When you select the Quit command from the launcher File menu, the launcher displays the short form shown in Figure 3-6 to make sure you selected Quit intentionally.

This sort of safeguard is nearly universal in graphical applications, but some people find it annoying. If you would prefer to take your chances with an occasional unintended shutdown, for the sake of having the launcher obey you unquestioningly, this example may be of interest. It shows how to redefine the Quit command to shut down the launcher without first displaying a query.

To discover what procedure implements the Quit command, examine the launcher definitions in ${WIND_BASE}/host/resource/tcl/Launch.tcl. Searching there for the string "Quit" leads us to the following menuButtonCreate invocation, which shows that the procedure to redefine is called launchQuit:

menuButtonCreate   File  Quit   Q  {launchQuit}

Example 3-2:  Alternate Quit Definition

The following redefinition of the launchQuit procedure eliminates the safeguard against leaving the launcher accidentally:

############################################################################## 
# launchQuit - abandon the launcher immediately 
# 
# This routine is a replacement for the launchQuit that comes with the 
# launcher; it runs when Quit is selected from the File menu in place of 
# the standard launchQuit, to avoid calling a confirmation dialog. 
# 
# SYNOPSIS: 
#   launchQuit 
# 
# RETURNS: N/A 
# 
# ERRORS: N/A 
#
proc launchQuit {} { exit }

An Open Command for the File Menu

Because editing files is a common development activity, it may be useful to invoke an editor from the launcher. This example defines a File>Open command to run the editor specified by the EDITOR environment variable. The example is based on the file selector built into the noticePost Tcl extension.

The code in this example collects the launcher initialization (adding commands to the File menu, both for this example and for Example 3-1) in an initialization procedure<<FIXME: , as recommended in F.4 Tcl Coding Conventions>>. In the example, the launcher executes launchExtInit, which adds entries to the File menu. Of these two new entries, Open calls launchFileOpen, which in turn calls launchEdit if the user selects a file to open.

Example 3-3:  Open Command and Customized File Menu Initialization

############################################################################## 
# 
# launchExtInit - collects personal launcher initialization 
# 
# This routine is invoked when the launcher begins executing, and collects 
# all the initialization (other than global and proc definitions)  
# defined in this file. 
# 
# SYNOPSIS: 
#   launchExtInit 
# 
# RETURNS: N/A 
# 
# ERRORS: N/A 
#
proc launchExtInit {} { # "Reinitialize" command for Launcher. # Adds item to File menu; calls Tcl "source" primitive directly. menuButtonCreate File "Re-Read Tcl" T { source ~/.wind/launch.tcl } # Add "Open" command to File menu menuButtonCreate File "Open..." O { launchFileOpen ;# defined in launch.tcl } }
############################################################################## # # launchFileOpen - called from File menu to run an editor on an arbitrary file # # This routine supports an Open command added to the File menu. It prompts # the user for a filename; if the user selects one, it calls launchEdit to # edit the file. # # SYNOPSIS: # launchFileOpen # # RETURNS: N/A # # ERRORS: N/A #
proc launchFileOpen {} { set result [noticePost fileselect "Open file" Open "*"] if {$result != ""} { launchEdit $result } }
############################################################################## # # launchEdit - run system editor on specified file # # This routine runs the system editor (as specified in the environment # variable EDITOR, or vi if EDITOR is undefined) on the file specified # in its argument. # # SYNOPSIS: # launchEdit fname # # PARAMETERS: # fname: the name of a file to edit # # RETURNS: N/A # # ERRORS: N/A #
proc launchEdit {fname} {
# we need to examine environment variables
global env
if { ([file readable $fname] && ![file isdirectory $fname]) || ([file writable [file dirname $fname]] && ![file exists $fname]) } then {
# We have an editable file # Use the EDITOR environment variable, with vi default
if [info exists env(EDITOR)] { set editor $env(EDITOR) } else { set editor vi }
if [string match "emacsc*" $editor] {
# looks like emacsclient. Don't run an xterm; just put this # in the background.
exec $editor $fname & } else {
# Run an xterm with the editor in it.
exec xterm -e $editor $fname & } } else {
# fname was unreadable or a directory
noticePost info "Cannot open: <<$fname>>" } }
############################################################################## # # launch.tcl - initialization for private extensions to launcher # # The following line executes when the launcher begins execution; it # calls all private launcher extensions defined in this file. #
launchExtInit