7.7   Tcl: CrossWind Customization

Like every other Tornado tool, the CrossWind graphical user interface is "soft" (amenable to customization) because it is written in Tcl, which is an interpreted language. Tornado API Guide: UI Tcl describes the graphical building blocks available; you can also study the Tcl implementation of CrossWind itself. You can find the source in host/resource/tcl/CrossWind.tcl.

7.7.1   Tcl: Debugger Initialization Files

You can write Tcl code to customize the debugger's graphical presentation in a file called .wind/crosswind.tcl under your home directory. Use this file to collect your custom modifications, or to incorporate shared customizations from a central repository of Tcl extensions at your site.

Recall that the debugger uses two separate Tcl interpreters. Previous sections described the .gdbinit and ~/.wind/gdb.tcl initialization files that initialize the debugger command language (see 7.6 Tcl: Debugger Automation).

The following outline summarizes the role of all the CrossWind customization files. The files are listed in the order in which they execute.

~/.wind/gdb.tcl
Use this file to customize the Tcl interpreter built into GDB itself (for example, to define Tcl procedures for new GDB commands). This file is unique to the CrossWind version of GDB.

~/.gdbinit
Use this file for any initialization you want to perform in GDB's command language rather than in Tcl. This file is not unique to CrossWind; it is shared by any other GDB configuration you may install.

${PWD}/.gdbinit
Akin to the .gdbinit in your home directory, this file also contains commands in GDB's command language, and is not unique to the CrossWind configuration of GDB. However, this file is specific to a particular working directory; thus it may be an appropriate place to record application-specific debugger settings.

~/.wind/crosswind.tcl
Use this file to customize the debugger's graphical presentation, using Tcl: for example, to define new buttons or menu commands. This file is unique to the CrossWind version of GDB.

You can prevent CrossWind from looking for the two .gdbinit files, if you choose, by setting the internal GDB parameter inhibit-gdbinit to yes. Because the initialization files execute in the order they are listed above, you have the opportunity to set this parameter before the debugger reads either .gdbinit file. To do this, insert the following line in your ~/.wind/gdb.tcl:

gdb set inhibit-gdbinit yes 

7.7.2   Tcl: Passing Control between the Two CrossWind Interpreters

You can use the following specialized Tcl commands to pass control between the two CrossWind Tcl interpreters.

uptcl
From the Tcl interpreter integrated with the GDB command parser, uptcl executes the remainder of the line in the CrossWind graphical-interface Tcl interpreter. uptcl does not return a result.

downtcl
From the graphical-interface layer, downtcl executes the remainder of the line in the Tcl interpreter integrated with GDB. The result of downtcl is whatever GDB output the command generates. Use downtcl rather than ttySend if your goal is to capture the result for presentation in the graphical layer.

ttySend
From the graphical-interface layer, ttySend passes its string argument to GDB, exactly as if you had typed the argument in the command panel. A newline is not assumed; if you are writing a command and want it to be executed, include the newline character (\n) at the end of the string. Use ttySend rather than downtcl if your goal is to make information appear in the command panel (this can be useful for providing information to other GDB prompts besides the command prompt).

The major use of uptcl is to experiment with customizing or extending the graphical interface. For example, if you have a file myXWind containing experimental Tcl code for extending the interface, you can try it out by entering the following in the command panel:

(gdb) tcl uptcl source myXWind

By contrast, downtcl and ttySend are likely to be embedded in Tcl procedures, because (in conjunction with the commands discussed in 7.6.3 Tcl: Invoking GDB Facilities) they are the path to debugger functionality from the graphical front end.

Most of the examples in 7.7.3 Tcl: Experimenting with CrossWind Extensions, below, center around calls to downtcl.

7.7.3   Tcl: Experimenting with CrossWind Extensions

The examples in this section use the Tcl extensions summarized in Table 7-3. For detailed descriptions of these and other Tornado graphical building blocks in Tcl, see Tornado API Guide: UI Tcl.

Table 7-3:  Tornado UI Tcl Extensions Used in Example 7-2.


Tcl Extension
 
Description
 

dialogCreate
 
Define the layout of a form (dialog box). Includes a list of all graphical controls (such as buttons, text boxes, lists). The description of each control ends with the name of a Tcl callback used when the control is acted on.
 
dialogPost
 
Display or update a named form (dialog).
 
dialogUnpost
 
Remove a form (dialog) from the screen.
 
dialogGetValue
 
Report the current value of a dialog graphical element (the contents of a text box, or the current selection in a list).
 
noticePost
 
Display a popup notice or a file selector.
 
menuButtonCreate
 
Add a command to an existing menu.
 
toolBarItemCreate button
 
Add a new button (and associated command string) to the button bar.
 
toolBarItemCreate space
 
Add space before new buttons in the button bar.
 

Tcl: "This" Buttons for C++

In C++ programs, one particular named value has great special interest: this, which is a pointer to the object where the currently executing function is a member.

Example 7-1 defines two buttons related to this:

The Tcl primitive catch is used in the second button definition in order to avoid propagating error conditions (for instance, if the buttons are pressed with no code loaded) from GDB back to the controlling CrossWind session. This does not prevent GDB from issuing the appropriate error messages to the command panel.

Example 7-1:  Buttons for C++ this Pointer

# Make a nice gap before new buttons 
 
toolBarItemCreate " " space 
 
# BUTTON: "t"     Print C++ "this" value. 
 
toolBarItemCreate " t " button { 
    ttySend "print this\n"  
} 
 
# BUTTON: "t*"    Launch "inspect" window on current C++ class (*this) 
 
toolBarItemCreate " t*" button { 
    catch {downtcl gdb display/W *this} 
}

Tcl: A List Command for the File Menu

Example 7-2 illustrates how to add extensions to the CrossWind graphical interface with a simple enhancement: adding a menu command to list the displayed program source centered on a particular line.

In Example 7-2, the procedure xwindList uses downtcl to run the GDB list command. To tie this into the graphical interface, the example adds a new command List from to the File menu. The new command displays a form (described in the dialogCreate call) to collect input specifying an argument to the list command. When input is complete, the form in turn runs xwindList, through a call-back attached to its OK button. Figure 7-14 shows the new menu command and form defined here (and the Example 7-3 menu command).

Example 7-2:  List Command

# FORM: a form to prompt for list argument 
# (part of "List from..." command addition to "File" menu) 
 
dialogCreate "List from?" -size 290 100 { 
    {text "line spec:" -hspan} 
    {button "OK" -left 2 -right 48 -bottom .+5 xwindList}  
    {button "Dismiss" -left 52 -right 98 -bottom .+5  
    {dialogUnpost "List from?"}} 
}
# MENU COMMAND: "List", additional entry under "File" menuButtonCreate File "List from..." S { dialogPost "List from?" }
############################################################################## # # xwindList - procedure for "List" command in CrossWind "File" menu # # This procedure sends a "list" command to GDB. It is intended to be # called from the "List from?" dialog (posted by the "Display" command # in the CrossWind "File" menu). Do not call it from other contexts; # it interacts with the dialog. # # SYNOPSIS: # xwindList # # RETURNS: N/A # # ERRORS: N/A #
proc xwindList {} { set lspec [dialogGetValue "List from?" "line spec:"] catch {downtcl gdb list $lspec} # gdb does not send back error indication, # but it does display any errors in command panel dialogUnpost "List from?" }

Figure 7-14:  List Menu Command and Form Defined in Example 7-2

Tcl: An Add-Symbols Command for the File Menu

As explained in What Modules to Debug, you sometimes need to tell the debugger explicitly to load symbols for modules that were downloaded to the target using other programs (such as the shell).

Example 7-3 illustrates a File menu command Add Symbols to handle this through the graphical user interface, instead of typing the add-symbol-file command.

Example 7-3:  Add-Symbols Command

# MENU COMMAND: "Add Symbols", additional entry under "File" 
 
menuButtonCreate File "Add Symbols..." S { xwindAddSyms }
############################################################################## # # xwindAddSyms - called from File menu to add symbols from chosen object file # # This routine implements the "Add Symbols" command in the File menu. # It prompts the user for a filename; if the user selects one, it tells # GDB to load symbols from that file. # # SYNOPSIS: # xwindAddSyms # # RETURNS: N/A # # ERRORS: N/A #
proc xwindAddSyms {} { set result [noticePost fileselect "Symbols from file" Add "*.\[o|out\]"] if {$result != ""} { # we violate good taste here by not capturing or testing the result # of catch, because GDB poats an error message in the command panel # when the file cannot be loaded. catch {downtcl gdb add-symbol-file $result} } }