Skip to main content

LHEATcl Plugin API

The LHEATcl Plugin is an enhanced version of the TCL Plugin version 2.0 source release. The version number of the current LHEATcl release is 2.0 despite the fact that it is the first official release in order to match the version number of the TCL plugin that it "descends" from. The LHEATcl Plugin adds the following extra features to the plugin:

  • The dash patch : This adds several missing things to the Tk canvas widget. These include dashed and stippled outlines, the "visitor" patch to allow easier extension of canvas capabilities, and postscript output for images. See the dash patch home page for details.
  • FitsTcl: This adds the ability to read and write FITS files. It is essentially a Tcl interface to cfitsio
  • POW: A scientific curve and image plotting and interface widget which uses the Tk canvas with several extensions to produced curve plots, images, contours, histograms, etc. Since y using the Tk canvas, user input can be done almost any way you wish.
  • The LHEA orbit library. This is currently under development and in release 2.0, only three functions are present which are built into the POW library, but in future releases, this will be a separate package adding spacecraft orbit calculation utility routines.
Follow the links above to get in depth information on any of the LHEATcl components. Documentation for the original Tcl plugin is here. What follows is a brief description of how the plugin works followed by some sample tclets.

What It is and How It Works

The "guts" of the LHEATcl plugin is a dynamically loadable library (DLL) containing the compiled object files from Tcl/Tk, FitsTcl, POW, etc. Currently, there is just one, monolithic LHEATcl DLL, unlike the LHEA standalone Tcl scripts such as fv where there one DLL for each package (Tcl, Tk, fitsTcl, POW, etc) . This library is placed in your browser's plugins directory. Currently Netscape4.x and Internet Explorer 3.x, 4.x, and 5.0 are supported. Netscape3.x is not supported because the Javascript we use to setup a window to run the tclet in doesn't work in Netscape 3.x. When your browser starts up it scans the plugins directory. If it finds the LHEATcl plugin library, it adds the LHEATcl plugin to its list of plugins and registers the plugin to process files of mime type "application/x-tcl". For details of how this information is stored in the library file, see the documentation for the Netscape plugin SDK.

Now when your browser encounters:

  • a URL that ends in ".tcl" or
  • a page that has mime type "application/x-tcl" or
  • a statement like:
 
<embed src=http://weefle.com/myapp.tcl type=application/x-tcl>
or
 
<embed script='label .l -text "Hello World"; pack .l' type=application/x-tcl>
it loads the DLL (".so" file in the Unix world). We had hoped to use a unique extension and mime type for LHEATclets rather than coopting the original "tcl" type, but bugs in the Windows version of Netscape prevented it. Luckily, the LHEATcl plugin should run any generic tclets without problems.

Loading the DLL creates a Tcl "interpreter" either as a thread or a separate process, depending on your configuration. The interpreter executes several initialization scripts (written in Tcl) and reads configuration parameters. The scripts are located in the user's .netscape/lheatclplug/2.0/* directories for UNIX and in the lheaplug/2.0/* directory for Windows. On the Mac, these scripts are located in the resource fork of the DLL. The configuration parameters are in files in the config/ directory and are used to setup security policies and a few other adjustable settings (on the Mac, these config files are in the extensions folder in the "Tool Command Language" folder).

Finally, the browser fetches the Tcl code (tclet) that started the whole process from the web server and the interpreter executes it.

Security "Policies" and Configuration Files

To expand slightly on the above description, when your browser loads the LHEATcl DLL and finishes running startup scripts, it spawns a slave interpreter and runs the tclet in the slave interpreter. The reason for this is that the slave interpreter is restricted from doing certain insecure things. These restrictions are implemented through security policies.

For a great deal more information about security policies, see the Tcl plugin manual pages, particularily the policy and plugin architecture pages. All of the files dealing with policy and configuration are in the config subdirectory of the plugin's runtime library directory. Most of the files in the config directory are responsible for implementing various named security policy. The code in each of these files specifies what specific features of Tcl are turned on or off for that policy. So when a tclet wants to use a feature such as opening a socket to another computer save files on the browser's machine it will need to ask for a security policy that allows the use of the desired feature. For instance, a tclet wanting to send Javascript commands to the browser would need to include the line: policy javascript If the origin URL of the tclet is allowed to invoke the "javascript" policy, tclet execution will proceed, if not, the process will abort.

The file that actually sets up the behavior of your plugin config/plugin.cfg. Most of this file sets up which origin URLs can use which policies. For instance, by default, the original Tcl plugin allowed the "home" policy for any tclet, whereas the fairly dangerous features of the "javascript" policy are only allowed if the origin URL is located at SUN Microsystems. There is a "lhea" policy which allows several necessary features for our programs. Unfortunately, there is a bug in MAKI (our first major production tclet) that prevents it from running under the "lhea" policy and we haven't had time to figure out how to fix this; therefore, the LHEATcl plugin currently installs configured so that any URL matching *.gsfc.nasa.gov for it's domain name is allowed to use the dangerous "trusted" policy.

The last few lines of "plugin.cfg" can be uncommented to set variables which allow some useful plugin features, primarily for debugging tclets:

TCL_PLUGIN_CONSOLE
If this is set to 1, a tk console window will pop up when a tclet loads. Typing Tcl commands into the console will execute them in the unrestricted *master* Tcl interpreter, not the restricted slave interpreter. If you want to send commands to the slave use the interp eval command. The interp slaves command can be used to find the name of the slave interpreter(s).
TCL_PLUGIN_LOGWINDOW
If set to 1, a window containing a fairly detailed log of what the plugin is doing pops up when a given tclet loads
TCL_PLUGIN_LOGFILE
Set this to the name of a file if you want to capture the log output from the plugin.
TCL_PLUGIN_WISH
Setting this to 1 causes the plugin to launch as a separate process instead of as a thread of your browser's process. On most platforms, this doesn't make much difference, but setting TCL_PLUGIN_WISH to 1 under Solaris is currently necessary because recent Solaris versions of Netscape were built under Solaris2.5 which had broken signal handling in threaded processes.

File IO in the Plugin

File IO in the LHEATcl plugin is somewhat complicated. By default, the plugin's security features disable writing files to the local machine entirely. However, fitsTcl's file writing does not implement any security features. The trusted policy allows unrestricted file writing on the local machine. The lhea policy allows the more limited persistent file writing. FITS file writing through fitsTcl doesn't work under Windows for the current version of the plugin. We will attempt to summarize the various possibilities here:

  1. Writing non-FITS files can be done with the standard Tcl commands (open, puts, etc.). If you use a 'policy trusted' statement, the files will appear in the current working directory of the browser process.
  2. If you use 'policy lhea' (or any policy which allows the "persist" feature) the files will appear in /tmp/username/persist/lhea/dir0. In Windows: '/tmp/username' will instead be the Windows temp directory; frequently this is C:/WINDOWS/temp. When using the persist feature, the total ammount of disk space used by persistent files is limited. See Tcl plugin documentation for details.
  3. You cannot read files from the browser's computer unless they are present in the persistent file area or you are using the 'trusted' policy.
  4. Using fitsTcl calls, you can read and write FITS files anywhere that the user is allowed to read or write files on the client machine. The default location is the current working directory of the browser process. There is no size limit.
  5. You can use the Tcl built-in http package or standard extension packages that provide ftp, etc. (as long as they're written in straight Tcl) to fetch files from URLs.
  6. For FITS files, you can pass a URL rather than a filename to the fitsTcl 'fits open' command and it will fetch the file using cfitsio's internal net drivers. Note: cfitsio net drivers currently only work on UNIX.

Known Problems and Considerations

There are a few known quirks in the plugin or its build that need to be allowed for.

On most Unix machines, if you resize the browser window containing a tclet, the browser will crash and core dump. This is a problem with the original Tcl plugin. We prevent this for MAKI by launching the tclet in it's own, non-resizable, browser window. See the example below for details on how to do this.

It would be safer, not so much to prevent malicious intent as to guard against catastrophic bugs, if we used the 'lhea' security policy rather than the 'trusted' security policy for MAKI. We are using some forbidden feature which we have not had the time to track down. "Your mileage may vary", so try to use the 'lhea' policy if you can. This does impose some strict limits on your code, the most obvious is probably the lack of the 'menu' widget. See Tcl plugin documents for details.

As mentioned above, if you want to use cfitsio net drivers, you are limited to Unix and for Solaris you must set TCL_PLUGIN_WISH equal to 1 in the plugin.cfg file. This is done by default in our prebuilt copies of the plugin.

If you need to rebuild and/or extend the LHEATcl plugin yourself, you are welcome to do so (read the SUN license agreement for full details on the legal status of the plugin, the terms are pretty generous). You may want to contact us to coordinate efforts if you're planning extensive improvements (send email to wasabi@oheasarc.gsfc.nasa.gov). The UNIX build is fairly straightforward, we use proprietary compilers where possible since that is how Netscape is usually built, but gcc should work fine. The Windows build is fairly torturous at present and requires both Borland C++ and Microsoft Visual C++ and is not for the faint of heart, or even weak of stomach, I suspect. The MacIntosh build uses CodeWarrior.

Examples

This example is a simple function plotter. It shows how to create powCurve objects and graph them.

#This is a simple example to plot any TCL expression
#ask for the trusted security policy (hopefully, next release, the lhea policy
#will be an option, but it's currently broken)
policy trusted

#load the POW features (it's built into the plugin as a "static package")
load "" pow

#make a place to put the POW window
frame .powholder 
grid .powholder -column 0 -row 0 -columnspan 4

#open up a POW window to plot stuff in
#arguments mean:
# "safe" - tell POW we're running in a browser so don't try to manage the X
#          color resources
# ".powholder"    - where to put the POW window
# "1"             - include the standard POW GUI (use 0 to suppress the POW
#                   GUI for more specialized applications)
powInit safe .powholder 1

#tell the POW window how big to be
.pow.pow configure -width 380 -height 380

#Get the function to plot
button .plotbutton -text "Plot Function" -command \
    {plotFunc $exprString $rMin $rMax}
grid .plotbutton -column 0 -row 1 -sticky ew -columnspan 2

set exprString {sin($x)}
entry .exprentry -textvariable exprString -width 40
grid .exprentry -column 2 -row 1 -sticky ew -columnspan 2

#Get the range they want
set rMin 0
label .minlab -text XMin
entry .minentry -textvariable rMin -width 10
grid .minlab  -column 0 -row 2 -sticky ew
grid .minentry -column 1 -row 2 -sticky ew

set rMax 6.2831853
label .maxlab -text XMax
entry .maxentry -textvariable rMax -width 10
grid .maxlab  -column 2 -row 2 -sticky ew
grid .maxentry -column 3 -row 2 -sticky ew

set ext 0



proc plotFunc {exprstring min max} {
    global ext    
#create a curve
    makeCurve $exprstring $min $max
#Check to see if a graph exists
    if {[powListGraphs] != "" } {
#add new curve to graph
	powPlotCurves MyFunctions "curve_$ext" 
#call function to rescale the graph to show all curves 
	powEndROI 1
    } else {
#no graph, make one
	powCreateGraph MyFunctions "curve_$ext" NULL NULL NULL NULL NULL 300 300
    }

}

proc makeCurve {exprstring min max} {
global ext
#make a new curve name
    incr ext
    set curve "curve_${ext}"
#calculate 100 curve points
    set deltx [expr double($max - $min)/100.0]
    set i 0
    catch {unset xvect}
    catch {unset yvect}
    for {set x $min} {$x < $max} {set x [expr $x + $deltx]} {
	lappend xvect $x
	lappend yvect [expr $exprstring]
	incr i
    }
#Make powData objects from TCL lists
    powCreateDataFromList xdata $xvect
    powCreateDataFromList ydata $yvect
    
#Make powVector objects from powData objects
    powCreateVector xvector xdata 0 $i NULL
    powCreateVector yvector ydata 0 $i NULL

#Make powCurve object from powVector objects
    powCreateCurve "curve_$ext" xvector NULL yvector NULL
    
}    

Now let's try a tclet with some fitsTcl calls. This will be a bit more complicated. Here's an annotated FITS file image display tclet:

#ask for the trusted security policy (hopefully, next release, the lhea policy
#will be an option, but it's currently broken)
policy trusted

#load the POW and fitsTcl features (they're built into the plugin as "static
#packages")
load "" pow
load "" fits

#make a place to put the POW window
frame .powholder 
grid .powholder -column 0 -row 0 -columnspan 2

#open up a POW window to plot stuff in
#arguments mean:
# "safe" - tell POW we're running in a browser so don't try to manage the X
#          color resources
# ".powholder"    - where to put the POW window
# "0"             - don't include the standard POW GUI (You might try 
#                   setting this to "1" for a more versatile tclet
powInit safe .powholder 1

#tell the POW window how big to be
.pow.pow configure -width 380 -height 380

button .imagebutton -text "Plot Image" -command {loadImage $imageURL}
grid .imagebutton -column 0 -row 1 -sticky ew

set imageURL "http://heasarc.gsfc.nasa.gov/wasabi/algol.fits"
entry .imageentry -textvariable imageURL -width 40
grid .imageentry -column 1 -row 1 -sticky ew


proc loadImage {url} {
    
#make a name for the graph:
set gname "MyGraph"
#make sure we don't reuse an existing name
set ext  0
while {[lsearch [powListGraphs] $gname] != -1} {
    incr ext
    set gname "${gname}_${ext}"
}


#for simplicity, in this example, we'll let cfitsio read the file.
#if you're running under Windows or MacOS, this means you can't use
#a URL, just a local file name. We could be more elaborate, but this
#is meant to be a *simple* example
#open the fits file (readonly)    
set infilehandle [fits open $url 0]

#load the image data into memory
set imghandle [$infilehandle load image]
    
#get the dimensions of the image
set dims [$infilehandle info imgdim]
set n1 [lindex $dims 0]
set n2 [lindex $dims 1]

#get the data type of the image 
set data_type [lindex [lindex [$infilehandle get keyword BITPIX] 0] 1]

#Now we work around a bug in the 2.0 version of the plugin, future versions
#will be able to use the BITPIX value for data type without translation
    set ppFitsDataType(8) 0
    set ppFitsDataType(16) 1
    set ppFitsDataType(32) 2
    set ppFitsDataType(-32) 3
    set ppFitsDataType(-64) 4
    set data_type $ppFitsDataType($data_type)


#Now a bit of Voodoo to deal with possible wierd file types:

#If the image has BZERO or BSCALE keywords in the header, fitsTcl will
#do the appropriate thing with them automatically, but the datatype returned
#will be floating point doubles (isn't FITS fun:)
if { ([catch {$infilehandle get keyword BZERO}] == 0) ||
     ([catch {$infilehandle get keyword BSCALE}] == 0) } {
    set data_type 4
}

#make a POW DATA object

powCreateData ${gname}_data $imghandle $data_type [expr $n1 * $n2] 0

#make a POW IMAGE object; the units (pixels, intensity) are arbitrary; since
#this is a general application, we don't know what they are

powCreateImage ${gname}_img ${gname}_data 0 0 $n1 $n2 0 1 0 1 pixels pixels intensity

#This will setup POW to use the Astronomical coordinate information
#in the file (if there is any) 
global powWCS
if { ! [catch  {$infilehandle get imgwcs} wcsString] } {
    set powWCS(${gname}_img) $wcsString
}

#we're done reading the file now
$infilehandle close

#make a POW Graph object which contains only our image

powCreateGraph $gname NULL ${gname}_img \
    pixels pixels NULL NULL 300 300

}

While it's not strictly a LHEATcl question, it is handy to know how to launch a tclet in a new console window using Javascript. Here's the code to make a button that launches MAKI (a LHEATcl applet) on a the test file algol.fits:

<FORM>
<INPUT TYPE="button" VALUE="Launch MAKI" onClick='goober()'>
<SCRIPT LANGUAGE="JavaScript">
function goober() {
var newWindow
var winwidth
var content

if (screen.availWidth > 850 ) {
    winwidth = "850"
} else {        
    winwidth = "800"
}

newWindow = window.open("","MAKI","scrollbars,menubar,height=" +
screen.availHeight + ",width=" + winwidth)

content="<embed src=http://heasarc.gsfc.nasa.gov/Tools/maki/MAKI.tcl "+
"type=application/x-tcl height=2000 width=" + winwidth + 
" url=http://heasarc.gsfc.nasa.gov/Tools/maki/algol.fits graphname=Algol>"
newWindow.document.write(content)
newWindow.document.close()
}
</SCRIPT> 
</FORM>

Tako/MAKI/LHEATcl Plugin help line
Last modified: Mon Dec 6 15:49:01 EST 1999